java.util.HashMap.values()

时间:2015-10-19 21:07:42

标签: java

是否保证java.util.Map的标准实现中的键和值以相同的顺序返回?例如,如果map包含映射x1 -> y1x2 -> 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()));
    }
}

4 个答案:

答案 0 :(得分:3)

来自HashMap docs

  

此课程不保证地图的顺序;特别是,它不保证订单会随着时间的推移保持不变。

答案 1 :(得分:3)

来自HashMap的文件,

  

此课程不保证地图的顺序;特别是,它不保证订单会随着时间的推移保持不变。

如果您查看其code,您会发现在致电put()后,最终会计算hashentry object已创建并添加到bucket array 1}}。我简化了代码的目的只是为了解释场景背后发生的事情。

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

同时检查,

Difference between HashMap, LinkedHashMap and TreeMap

答案 2 :(得分:2)

查看http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/HashMap.java#HashMap.values%28%29,我猜它是有效的,因为KeyIterator和ValueIterator都扩展了HashIterator。

但是,只有当你不同时改变HashMap时才会这样做,例如在调用keySet()和values()之间添加和删除项目,因为这可以更改桶大小,并且HashIterator的行为会有所不同。

答案 3 :(得分:1)

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

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());
  }
}

我明白了:

[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]

这个简单的例子似乎表明虽然HashMap不会保留插入顺序,但它似乎确实保留了键和值的相对顺序。

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