如何有效地遍历 Java Map 中的每个条目?

如果我有一个用 Java 实现Map接口的对象,并且希望对其中包含的每一对进行迭代,那么遍历该映射的最有效方法是什么?

元素的顺序是否取决于我对接口的特定映射实现?

答案

Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

表格(性能测试,取决于地图大小)

100     600      1100     1600     2100
test10    0.333    1.631    2.752    5.937    8.024
test3     0.309    1.971    4.147    8.147   10.473
test6     0.372    2.190    4.470    8.322   10.531
test1     0.405    2.237    4.616    8.645   10.707
test2     0.376    2.267    4.809    8.403   10.910
test7     0.473    2.448    5.668    9.790   12.125
test9     0.565    2.830    5.952   13.220   16.965
test4     0.808    5.012    8.813   13.939   17.407
test5     0.810    5.104    8.533   14.064   17.422
test8     5.173   12.499   17.351   24.671   30.403

所有测试都在GitHub 上

在 Java 8 中,您可以使用新的 lambdas 功能来快速干净地完成它:

Map<String,String> map = new HashMap<>();
 map.put("SomeKey", "SomeValue");
 map.forEach( (k,v) -> [do something with key and value] );

 // such as
 map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));

kv的类型将由编译器推断,并且不再需要使用Map.Entry

十分简单!

是的,顺序取决于特定的 Map 实现。

@ ScArcher2 具有更优雅的 Java 1.5 语法 。在 1.4 中,我将执行以下操作:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}

遍历地图的典型代码是:

Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
    String key = entry.getKey();
    Thing thing = entry.getValue();
    ...
}

HashMap是规范的地图实现,并且不做任何保证(或者,如果不对其执行任何变异操作,则它不应该更改顺序)。 SortedMap将根据键或Comparator (如果提供)的自然顺序返回条目。 LinkedHashMap将根据其构造方式以插入顺序或访问顺序返回条目。 EnumMap以键的自然顺序返回条目。

(更新:我认为这不再成立。 )注意, IdentityHashMap entrySet迭代器当前具有一个特殊的实现,该实现为entrySet每个项目都返回相同的Map.Entry实例!但是,每次有新的迭代器前进Map.Entry被更新。

使用迭代器和泛型的示例:

Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Map.Entry<String, String> entry = entries.next();
  String key = entry.getKey();
  String value = entry.getValue();
  // ...
}

这是一个两部分的问题:

如何遍历 Map 的条目 -@ ScArcher2 已经完美地回答了这一问题。

迭代的顺序是什么 - 如果您仅使用Map ,那么严格来说, 没有排序保证 。因此,您不应真正依赖任何实现所给出的顺序。但是, SortedMap界面扩展了Map并提供了您所要查找的内容 - 实现将给出一致的排序顺序。

NavigableMap是另一个有用的扩展 - 这是SortedMap具有其他方法,可以根据键集中的有序位置查找条目。因此,这有可能消除了首先进行迭代的需要 - 您可以在使用higherEntrylowerEntryceilingEntryfloorEntry方法之后找到要访问的特定entrydescendingMap方法甚至为您提供了一种反转遍历顺序的显式方法。

有几种方法可以遍历地图。

这是通过在地图中存储一百万个键值对并在地图上进行迭代来比较存储在地图中的通用数据集的性能。

1)在每个循环中使用entrySet()

for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
    entry.getKey();
    entry.getValue();
}

50 毫秒

2)在每个循环中使用keySet()

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 毫秒

3)使用entrySet()和迭代器

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 毫秒

4)使用keySet()和迭代器

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 毫秒

我已经提到了this link

正确的方法是使用公认的答案,因为它是最有效的。我发现以下代码看起来更干净。

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}

仅供参考,如果您仅对地图的键 / 值感兴趣,而对其他键 / 值不感兴趣,则也可以使用map.keySet()map.values()