java.util.HashMap.values()的迭代顺序

java.util.HashMap.values()的迭代顺序,java,Java,是否保证java.util.Map的标准实现中的键和值以相同的顺序返回?例如,如果map包含映射x1->y1和x2->y2,那么如果keySet()迭代产生x1,x2,是否保证values()迭代产生y1,y2,而不是y2,y1?我还没有看到任何地方保证这是真的,但它似乎起了作用。有谁能证实或否定这个前提并给出反例 public class MapsTest { @Test public void hashMapKeysAndValuesAreInSameOrder() {

是否保证
java.util.Map
的标准实现中的键和值以相同的顺序返回?例如,如果map包含映射
x1->y1
x2->y2
,那么如果
keySet()
迭代产生
x1,x2
,是否保证
values()
迭代产生
y1,y2
,而不是
y2,y1
?我还没有看到任何地方保证这是真的,但它似乎起了作用。有谁能证实或否定这个前提并给出反例

public class MapsTest {
    @Test
    public void hashMapKeysAndValuesAreInSameOrder() {
        assertKeysAndValuesAreInSameOrder(new HashMap<>());
    }

    @Test
    public void treeMapKeysAndValuesAreInSameOrder() {
        assertKeysAndValuesAreInSameOrder(new TreeMap<>());
    }

    private void assertKeysAndValuesAreInSameOrder(Map<Integer, Integer> map) {
        Random random = new Random();
        IntStream.range(0, 100000).map(i -> random.nextInt()).forEach(i -> map.put(i, i));
        assertEquals(new ArrayList<>(map.keySet()), new ArrayList<>(map.values()));
    }
}
公共类映射测试{
@试验
public void HashMapKeysandValuesReinsameOrder(){
AssertKeysandValuesReinsameOrder(新的HashMap());
}
@试验
public void treemapkeyandvaluesareinsameorder(){
AssertKeysandValuesReinsameOrder(新树映射());
}
私有无效资产KeysandValuesReinsameOrder(映射){
随机=新随机();
range(01000).map(i->random.nextInt()).forEach(i->map.put(i,i));
assertEquals(新ArrayList(map.keySet()),新ArrayList(map.values());
}
}
来自:

此类不保证地图的顺序;特别是,它不能保证订单在一段时间内保持不变

根据

此类不保证地图的顺序;特别是,它不能保证订单在一段时间内保持不变

如果查看its,您将发现,一旦调用
put()
,最终计算出
hash
,就会创建
条目对象并将其添加到
存储桶数组中。我过度简化了代码的目的,只是为了解释幕后发生的事情

如果您想要保证订单,请根据您的要求使用或

还查,

看看,我猜它是有效的,因为KeyIterator和ValueIterator都扩展了HashIterator


但是,只有在同时不更改HashMap的情况下才能这样做,例如在调用keySet()和values()之间添加和删除项,因为这会改变bucket大小,HashIterator的行为也会有所不同。

有趣的问题。我试了一下。键的相对顺序似乎与值保持同步

import java.util.*;
public class MapClass {
public static Map<String, Integer> map = new HashMap<>();

  public static void main (String[] args){
    map.put("first", 1);
    map.put("second", 2);
    map.put("third", 3);
    map.put("fourth", 4);
    map.put("fifth", 5);

    System.out.println(map.keySet());
    System.out.println(map.values());

    map.put("sixth", 6);
    System.out.println(map.keySet());
    System.out.println(map.values());

    map.remove("first");
    System.out.println(map.keySet());
    System.out.println(map.values());
  }
}
这个简单的例子似乎表明,虽然
HashMap
不会保留插入顺序,但它似乎确实保留了键和值的相对顺序


虽然keyset()和values()不保证任何顺序,但它似乎会为多次调用返回相同的顺序。正如上面的评论所说,即使你可以依赖它,你是否应该也值得怀疑。

我看到了这句话,但我认为它没有说明键的顺序()和值()的关系。它可以,但它没有。我想知道是否有人能给我举个例子。我想ConcurrentModificationException会被抛出。而且这些映射不是线程安全的,所以并发性对我来说不是问题。我不认为你可以依赖它,因为
values()
的文档中没有提到这一点。我猜这个特性是公共契约的一部分,尽管它没有文档化。顺便说一句,我还记得Linus Torvald的帖子“我们永远不会破坏用户空间”。测试仍然通过
…forEach(I->{map.put(I,I);map.values();}
如果你执行System.out.println(map.keySet());,然后添加100000项,再次删除所有100000项,然后打印map.values(),您可能会得到不同的结果…使用
TreeMap
的情况相同?所有迭代器都扩展了
PrivateEntryIterator
TreeMap是一个SortedMap。因此需要在所有迭代器上保持相同的顺序。“映射按照其键的自然顺序排序,或者由排序映射创建时通常提供的比较器进行排序。当迭代排序映射的集合视图(由entrySet、keySet和values方法返回)时,会反映此顺序。还提供了一些附加操作来利用排序。”。(此界面类似于SortedSet的地图。)“这篇文章是关于键()和值()的相对顺序,而不是关于键()的绝对顺序。
[third, fifth, fourth, first, second]
[3, 5, 4, 1, 2]
[sixth, third, fifth, fourth, first, second]
[6, 3, 5, 4, 1, 2]
[sixth, third, fifth, fourth, second]
[6, 3, 5, 4, 2]