如何有效地迭代 Java Map 中的每个条目?

Posted

技术标签:

【中文标题】如何有效地迭代 Java Map 中的每个条目?【英文标题】:How do I efficiently iterate over each entry in a Java Map? 【发布时间】:2010-09-07 23:53:08 【问题描述】:

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

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

【问题讨论】:

在 Java 8 中使用 Lambda 表达式:***.com/a/25616206/1503859 Java 8:***.com/questions/46898/… 【参考方案1】:

这些是迭代HashMap的所有可能方式。

HashMap<Integer,String> map=new HashMap<Integer,String>();
    map.put(1,"David");  //Adding elements in Map
    map.put(2,"John");
    map.put(4,"Samyuktha");
    map.put(3,"jasmin");
    System.out.println("Iterating Hashmap...");

    //way 1 (java 8 Method)
    map.forEach((key, value) -> 
        System.out.println(key+" : "+ value);
    );

    //way 2 (java 7 Method)
    for(Map.Entry me : map.entrySet())
        System.out.println(me.getKey()+" "+me.getValue());
    

    //way 3 (Legacy type to iterate HashMap)
    Iterator iterator = map.entrySet().iterator();//map.keySet().iterator()
    while (iterator.hasNext())
    
        Map.Entry me =(Map.Entry)iterator.next();
        System.out.println(me.getKey()+" : "+ me.getValue());
    
    

【讨论】:

【参考方案2】:
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) 
    System.out.println(entry.getKey() + "/" + entry.getValue());

在 Java 10+ 上:

for (var entry : map.entrySet()) 
    System.out.println(entry.getKey() + "/" + entry.getValue());

【讨论】:

如果你这样做了,那么它就不起作用了,因为 Entry 是 Map 中的一个嵌套类。 java.sun.com/javase/6/docs/api/java/util/Map.html 您可以将导入写为“import java.util.Map.Entry;”它会起作用的。 @Pureferret 您可能想要使用迭代器的唯一原因是如果您需要调用它的remove 方法。如果是这种情况,this other answer 会向您展示如何操作。否则,如上答案所示的增强循环是要走的路。 我相信 Map.Entry 的形式比将内部类导入当前命名空间更清晰。 请注意,如果您只想遍历值或键,则可以使用map.values()map.keySet()【参考方案3】:

您可以搜索键,在键的帮助下,您可以找到映射的关联值,因为映射具有唯一键,看看当键重复here或@时会发生什么987654322@.

演示图:

 Map<String, String> map = new HashMap();
  map.put("name", "Name");
  map.put("age", "23");
  map.put("address", "NP");
  map.put("faculty", "BE");
  map.put("major", "CS");
  map.put("head", "MDK");
 

仅获取密钥,您可以像这样使用map.keySet();

for(String key : map.keySet()) 
      System.out.println(key);
  

仅获取价值,您可以像这样使用map.values();

      for(String value : map.values()) 
      System.out.println(value);
  

要同时获取键及其值,您仍然可以使用map.keySet(); 并获取其对应的值,如下所示:

 //this prints the key value pair
  for (String k : map.keySet()) 
        System.out.println(k + " " + map.get(k) + " ");
    

map.get(key) 给出该键指向的值。

【讨论】:

【参考方案4】:

遍历地图的典型代码是:

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 迭代器目前有一个特殊的实现,它为 @ 中的每个项目返回相同的 Map.Entry 实例987654330@!但是,每次新的迭代器前进时,Map.Entry 都会更新。

【讨论】:

EnumMap 和 IdentityHashMap 也有这种特殊的行为 "LinkedHashMap 将返回 [...] 访问顺序 [...] 中的条目...所以您按访问顺序访问元素?要么是重言式,要么是一些有趣的东西,可以使用题外话。 ;-) @jpaugh 仅直接访问LinkedHashMap 计数。通过iteratorspliteratorentrySet等,请勿修改顺序。 1. 虽然如果? 2. 最后一段可能会受益于复习。【参考方案5】:

排序将始终取决于特定的地图实现。 使用 Java 8,您可以使用以下任何一种:

map.forEach((k,v) ->  System.out.println(k + ":" + v); );

或者:

map.entrySet().forEach((e) -> 
            System.out.println(e.getKey() + " : " + e.getValue());
        );

结果将是相同的(相同的顺序)。地图支持的 entrySet,因此您获得相同的订单。第二个很方便,因为它允许您使用 lambda,例如如果您只想打印大于 5 的 Integer 对象:

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

下面的代码显示了通过 LinkedHashMap 和普通 HashMap 的迭代(示例)。您会看到顺序不同:

public class HMIteration 


    public static void main(String[] args) 
        Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
        Map<Object, Object> hashMap = new HashMap<>();

        for (int i=10; i>=0; i--) 
            linkedHashMap.put(i, i);
            hashMap.put(i, i);
        

        System.out.println("LinkedHashMap (1): ");
        linkedHashMap.forEach((k,v) ->  System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); );

        System.out.println("\nLinkedHashMap (2): ");

        linkedHashMap.entrySet().forEach((e) -> 
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        );


        System.out.println("\n\nHashMap (1): ");
        hashMap.forEach((k,v) ->  System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); );

        System.out.println("\nHashMap (2): ");

        hashMap.entrySet().forEach((e) -> 
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        );
    

输出:

LinkedHashMap (1):
10 (#=10):10, 9 (#=9):9, 8 (#=8):8, 7 (#=7):7, 6 (#=6):6, 5 (#=5):5, 4 (#=4):4, 3 (#=3):3, 2 (#=2):2, 1 (#=1):1, 0 (#=0):0,
LinkedHashMap (2):
10 : 10, 9 : 9, 8 : 8, 7 : 7, 6 : 6, 5 : 5, 4 : 4, 3 : 3, 2 : 2, 1 : 1, 0 : 0,
HashMap (1):
0 (#:0):0, 1 (#:1):1, 2 (#:2):2, 3 (#:3):3, 4 (#:4):4, 5 (#:5):5, 6 (#:6):6, 7 (#:7):7, 8 (#:8):8, 9 (#:9):9, 10 (#:10):10,
HashMap (2):
0 : 0, 1 : 1, 2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10,

【讨论】:

【参考方案6】:

在地图中,可以迭代keys 和/或values 和/或both (e.g., entrySet) 取决于一个人的兴趣_喜欢:

    遍历地图的keys -&gt; keySet()

     Map<String, Object> map = ...;
    
     for (String key : map.keySet()) 
         //your Business logic...
     
    

    遍历地图的values -&gt; values()

     for (Object value : map.values()) 
         //your Business logic...
     
    

    遍历地图的both -&gt; entrySet()

     for (Map.Entry<String, Object> entry : map.entrySet()) 
         String key = entry.getKey();
         Object value = entry.getValue();
         //your Business logic...
     
    

此外,还有 3 种不同的方法可以遍历 HashMap。它们如下:

//1.
for (Map.Entry entry : hm.entrySet()) 
    System.out.print("key,val: ");
    System.out.println(entry.getKey() + "," + entry.getValue());


//2.
Iterator iter = hm.keySet().iterator();
while(iter.hasNext()) 
    Integer key = (Integer)iter.next();
    String val = (String)hm.get(key);
    System.out.println("key,val: " + key + "," + val);


//3.
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) 
    Map.Entry entry = (Map.Entry) it.next();
    Integer key = (Integer)entry.getKey();
    String val = (String)entry.getValue();
    System.out.println("key,val: " + key + "," + val);

【讨论】:

【参考方案7】:

有几种方法可以迭代地图。请参考以下代码。

当您使用迭代器接口迭代地图时,您必须使用Entry&lt;K,V&gt;entrySet()

看起来像这样:

    import java.util.*;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;

    public class IteratMapDemo

        public static void main(String arg[])
            Map<String, String> mapOne = new HashMap<String, String>();
            mapOne.put("1", "January");
            mapOne.put("2", "February");
            mapOne.put("3", "March");
            mapOne.put("4", "April");
            mapOne.put("5", "May");
            mapOne.put("6", "June");
            mapOne.put("7", "July");
            mapOne.put("8", "August");
            mapOne.put("9", "September");
            mapOne.put("10", "Octomber");
            mapOne.put("11", "November");
            mapOne.put("12", "December");

            Iterator it = mapOne.entrySet().iterator();
            while(it.hasNext())
            
                Map.Entry me = (Map.Entry) it.next();
                //System.out.println("Get Key through While loop = " + me.getKey());
            
            for(Map.Entry<String, String> entry:mapOne.entrySet())
                //System.out.println(entry.getKey() + "=" + entry.getValue());
            

            for (Object key : mapOne.keySet()) 
                System.out.println("Key: " + key.toString() + " Value: " +
                                   mapOne.get(key));
            
        
    

【讨论】:

keySet() 很慢【参考方案8】:

一个有效的 Map 迭代解决方案是从 Java 5 到 Java 7 的 for 循环。这里是:

for (String key : phnMap.keySet()) 
    System.out.println("Key: " + key + " Value: " + phnMap.get(key));

从 Java 8 开始,您可以使用 lambda 表达式来迭代 Map。这是一个增强的forEach

phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));

如果你想为 lambda 写一个条件,你可以这样写:

phnMap.forEach((k,v)->
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k))
        System.out.println("Hello abc");
    
);

【讨论】:

【参考方案9】:
Map<String, String> map = 
for (Map.Entry<String, String> entry : map.entrySet()) 
    MapKey = entry.getKey() 
    MapValue = entry.getValue();

【讨论】:

【参考方案10】:

从 Java 10 开始,您可以使用局部变量推断(也称为“var”)来减少许多已经可用的答案的臃肿。例如:

for (var entry : map.entrySet()) 
    System.out.println(entry.getKey() + " : " + entry.getValue());

【讨论】:

【参考方案11】:

使用 Java 8,您可以使用 forEach 和 lambda 表达式迭代 Map,

map.forEach((k, v) -> System.out.println((k + ":" + v)));

【讨论】:

【参考方案12】:

对于Eclipse Collections,您将在MapIterable 接口上使用forEachKeyValue 方法,该方法由MutableMapImmutableMap 接口及其实现继承。

MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

使用匿名内部类,可以编写如下代码:

final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()

    public void value(Integer key, String value)
    
        result.add(key + value);
    
);
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

注意:我是 Eclipse Collections 的提交者。

【讨论】:

【参考方案13】:

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

如果循环键的效率是您的应用的优先考虑因素,则选择一个Map 实现,以按您想要的顺序维护键。

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

是的,当然。

一些Map 实现承诺一定的迭代顺序,而另一些则不承诺。 Map 的不同实现保持键值对的不同顺序。

请参阅我创建的此表,该表总结了与 Java 11 捆绑的各种 Map 实现。具体来说,请注意 iteration order 列。点击/点击放大。

您可以看到有四个Map 实现维护一个顺序

TreeMap ConcurrentSkipListMap LinkedHashMap EnumMap

NavigableMap接口

其中两个实现了NavigableMap 接口:TreeMapConcurrentSkipListMap

较旧的SortedMap 接口被较新的NavigableMap 接口有效地取代。但是您可能会发现仅实现旧接口的 3rd 方实现。

自然秩序

如果您想要一个 Map 保持其对按密钥的“自然顺序”排列,请使用 TreeMapConcurrentSkipListMap。术语“自然顺序”是指键的类实现ComparablecompareTo方法返回的值用于排序比较。

自定义订单

如果您想为您的键指定自定义排序例程以用于维护排序顺序,请传递适合您的键类的Comparator 实现。使用TreeMapConcurrentSkipListMap,传递您的Comparator

原始广告订单

如果您希望成对的地图按照您将它们插入地图时的原始顺序保留,请使用LinkedHashMap

枚举定义顺序

如果您使用DayOfWeekMonth 等枚举作为键,请使用EnumMap 类。这个类不仅高度被优化为使用非常少的内存并且运行非常快,它还按照枚举定义的顺序维护你的对。以DayOfWeek为例,迭代时首先找到DayOfWeek.MONDAY的key,最后找到DayOfWeek.SUNDAY的key。

其他注意事项

在选择Map 实现时,还要考虑:

空值。一些实现禁止/接受 NULL 作为键和/或值。 并发。如果要跨线程操作映射,则必须使用支持并发的实现。或者用Collections::synchronizedMap 包裹地图(不太推荐)。

上面的图表涵盖了这两个注意事项。

【讨论】:

对一个迟到的答案发表评论(但信息量很大)。 +1 我提到EnumMap,因为这是我第一次听说它。在很多情况下这可能会派上用场。【参考方案14】:

Map.forEach

如果简单地使用Map::forEach 将键和值都传递给您的BiConsumer 怎么样?

map.forEach((k,v)->
    System.out.println(k+"->"+v);
);

【讨论】:

Answer by Lova Chittumuri 对此进行了介绍。在高度支持的Answer by Viacheslav Vedenin 中也被列为第 3 项。 但仅在 API 标签 24 中可用【参考方案15】:

迭代Map 非常简单。

for(Object key: map.keySet())
   Object value= map.get(key);
   //Do your stuff

例如,您有一个Map&lt;String, int&gt; data;

for(Object key: data.keySet())
  int value= data.get(key);

【讨论】:

嗯,这太慢了,因为首先获取密钥,然后是条目。替代方法:获取 entrySets,然后为每个 entryset 键和值【参考方案16】:

为了总结其他答案并将它们与我所知道的相结合,我找到了 10 种主​​要方法来做到这一点(见下文)。另外,我写了一些性能测试(见下面的结果)。例如,如果我们想找到一个映射的所有键和值的总和,我们可以这样写:

    使用 iteratorMap.Entry

    long i = 0;
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) 
        Map.Entry<Integer, Integer> pair = it.next();
        i += pair.getKey() + pair.getValue();
    
    

    使用 foreachMap.Entry

    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) 
        i += pair.getKey() + pair.getValue();
    
    

    在 Java 8 中使用 forEach

    final long[] i = 0;
    map.forEach((k, v) -> i[0] += k + v);
    

    使用 keySetforeach

    long i = 0;
    for (Integer key : map.keySet()) 
        i += key + map.get(key);
    
    

    使用 keySetiterator

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) 
        Integer key = itr2.next();
        i += key + map.get(key);
    
    

    使用 forMap.Entry

    long i = 0;
    for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) 
        Map.Entry<Integer, Integer> entry = entries.next();
        i += entry.getKey() + entry.getValue();
    
    

    使用 Java 8 流 API

    final long[] i = 0;
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
    

    使用 Java 8 Stream API 并行

    final long[] i = 0;
    map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
    

    使用Apache CollectionsIterableMap

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) 
        i += it.next() + it.getValue();
    
    

    使用 MutableMap 的 Eclipse (CS) 集合

    final long[] i = 0;
    mutableMap.forEachKeyValue((key, value) -> 
        i[0] += key + value;
    );
    

性能测试(模式 = AverageTime,系统 = Windows 8.1 64 位,Intel i7-4790 3.60 GHz,16 GB)

    对于小地图(100 个元素),得分 0.308 是最好的

    Benchmark                          Mode  Cnt  Score    Error  Units
    test3_UsingForEachAndJava8         avgt  10   0.308 ±  0.021  µs/op
    test10_UsingEclipseMap             avgt  10   0.309 ±  0.009  µs/op
    test1_UsingWhileAndMapEntry        avgt  10   0.380 ±  0.014  µs/op
    test6_UsingForAndIterator          avgt  10   0.387 ±  0.016  µs/op
    test2_UsingForEachAndMapEntry      avgt  10   0.391 ±  0.023  µs/op
    test7_UsingJava8StreamApi          avgt  10   0.510 ±  0.014  µs/op
    test9_UsingApacheIterableMap       avgt  10   0.524 ±  0.008  µs/op
    test4_UsingKeySetAndForEach        avgt  10   0.816 ±  0.026  µs/op
    test5_UsingKeySetAndIterator       avgt  10   0.863 ±  0.025  µs/op
    test8_UsingJava8StreamApiParallel  avgt  10   5.552 ±  0.185  µs/op
    

    对于包含 10000 个元素的地图,得分 37.606 是最好的

    Benchmark                           Mode   Cnt  Score      Error   Units
    test10_UsingEclipseMap              avgt   10    37.606 ±   0.790  µs/op
    test3_UsingForEachAndJava8          avgt   10    50.368 ±   0.887  µs/op
    test6_UsingForAndIterator           avgt   10    50.332 ±   0.507  µs/op
    test2_UsingForEachAndMapEntry       avgt   10    51.406 ±   1.032  µs/op
    test1_UsingWhileAndMapEntry         avgt   10    52.538 ±   2.431  µs/op
    test7_UsingJava8StreamApi           avgt   10    54.464 ±   0.712  µs/op
    test4_UsingKeySetAndForEach         avgt   10    79.016 ±  25.345  µs/op
    test5_UsingKeySetAndIterator        avgt   10    91.105 ±  10.220  µs/op
    test8_UsingJava8StreamApiParallel   avgt   10   112.511 ±   0.365  µs/op
    test9_UsingApacheIterableMap        avgt   10   125.714 ±   1.935  µs/op
    

    对于有 100000 个元素的地图,得分 1184.767 是最好的

    Benchmark                          Mode   Cnt  Score        Error    Units
    test1_UsingWhileAndMapEntry        avgt   10   1184.767 ±   332.968  µs/op
    test10_UsingEclipseMap             avgt   10   1191.735 ±   304.273  µs/op
    test2_UsingForEachAndMapEntry      avgt   10   1205.815 ±   366.043  µs/op
    test6_UsingForAndIterator          avgt   10   1206.873 ±   367.272  µs/op
    test8_UsingJava8StreamApiParallel  avgt   10   1485.895 ±   233.143  µs/op
    test5_UsingKeySetAndIterator       avgt   10   1540.281 ±   357.497  µs/op
    test4_UsingKeySetAndForEach        avgt   10   1593.342 ±   294.417  µs/op
    test3_UsingForEachAndJava8         avgt   10   1666.296 ±   126.443  µs/op
    test7_UsingJava8StreamApi          avgt   10   1706.676 ±   436.867  µs/op
    test9_UsingApacheIterableMap       avgt   10   3289.866 ±  1445.564  µs/op
    

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

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

          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。

【讨论】:

@Viacheslav :非常好的答案。只是想知道在您的基准测试中如何通过捕获 lambdas 来阻碍 Java8 api...(例如,long sum = 0; map.forEach( /* accumulate in variable sum*/); 捕获了 sum long,这可能比例如 stream.mapToInt(/*whatever*/).sum 慢。当然,您不能总是避免捕获状态,但这可能是替补席的合理补充。 @ZhekaKozlov:看看惊人的大错误值。考虑到x±e 的测试结果意味着在x-ex+e 的区间内有结果,因此最快的结果(1184.767±332.968)范围从8521518,而第二慢的( 1706.676±436.867) 在12702144 之间运行,所以结果仍然有很大的重叠。现在看看最慢的结果3289.866±1445.564,这意味着在18444735 之间存在分歧,您知道这些测试结果毫无意义。 比较一下 HashMap、LinkedHashMap 和 TreeMap 的 3 个主要实现怎么样? #1 和#6 完全相同。使用whilefor 循环并不是一种不同的迭代技术。而且我很惊讶它们在您的测试中存在这样的差异——这表明测试没有正确地与与您打算测试的事物无关的外部因素隔离开来。 #8 是一个可怕的例子,因为 parallel 现在添加到 i 时会出现竞争条件。【参考方案17】:

使用 Java 7

Map<String,String> sampleMap = new HashMap<>();
for (sampleMap.Entry<String,String> entry : sampleMap.entrySet()) 
    String key = entry.getKey();
    String value = entry.getValue();

    /* your Code as per the Business Justification  */


使用 Java 8

Map<String,String> sampleMap = new HashMap<>();

sampleMap.forEach((k, v) -> System.out.println("Key is :  " + k + " Value is :  " + v));

【讨论】:

【参考方案18】:

我喜欢连接一个计数器,然后保存计数器的最终值;

int counter = 0;
HashMap<String, String> m = new HashMap<String, String>();
for(int i = 0;i<items.length;i++)

m.put("firstname"+i, items.get(i).getFirstName());
counter = i;


m.put("recordCount",String.valueOf(counter));

那么当你要检索时:

int recordCount = Integer.parseInf(m.get("recordCount"));
for(int i =0 ;i<recordCount;i++)

System.out.println("First Name :" + m.get("firstname"+i));

【讨论】:

【参考方案19】:

Lambda 表达式 Java 8

在 Java 1.8 (Java 8) 中,通过使用类似于 Iterable 中的迭代器的聚合操作(流操作)中的 forEach 方法,这变得更加容易 界面。

只需将下面的语句复制粘贴到您的代码中,然后将 HashMap 变量从 hm 重命名为您的 HashMap 变量即可打印出键值对。

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
 *     Logic to put the Key,Value pair in your HashMap hm
 */

// Print the key value pair in one line.

hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));

// Just copy and paste above line to your code.

以下是我尝试使用 Lambda 表达式 的示例代码。这东西太酷了。一定要试试。

HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
    Random rand = new Random(47);
    int i = 0;
    while(i < 5) 
        i++;
        int key = rand.nextInt(20);
        int value = rand.nextInt(50);
        System.out.println("Inserting key: " + key + " Value: " + value);
        Integer imap = hm.put(key, value);
        if( imap == null) 
            System.out.println("Inserted");
         else 
            System.out.println("Replaced with " + imap);
                       
    

    hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));

Output:

Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11

同样可以使用 Spliterator

Spliterator sit = hm.entrySet().spliterator();

更新


包括指向 Oracle Docs 的文档链接。 有关 Lambda 的更多信息,请访问 link 并且必须阅读 Aggregate Operations,对于 Spliterator,请访问 link。

【讨论】:

【参考方案20】:

Java 8

我们有接受lambda expression 的forEach 方法。我们也有stream API。考虑一张地图:

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

迭代键:

sample.keySet().forEach((k) -> System.out.println(k));

迭代值:

sample.values().forEach((v) -> System.out.println(v));

迭代条目(使用 forEach 和 Streams):

sample.forEach((k,v) -> System.out.println(k + ":" + v)); 
sample.entrySet().stream().forEach((entry) -> 
            Object currentKey = entry.getKey();
            Object currentValue = entry.getValue();
            System.out.println(currentKey + ":" + currentValue);
        );

流的优势在于,如果我们愿意,它们可以很容易地并行化。我们只需要使用parallelStream() 代替上面的stream()

forEachOrderedforEach 有流? forEach 不遵循遇到顺序(如果已定义),并且与 forEachOrdered 一样,本质上是不确定的。所以forEach 不保证订单会被保留。另请查看this 了解更多信息。

【讨论】:

【参考方案21】:

Java 8 最紧凑:

map.entrySet().forEach(System.out::println);

【讨论】:

【参考方案22】:

使用 Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));

【讨论】:

【参考方案23】:

有很多方法可以做到这一点。下面是几个简单的步骤:

假设你有一张这样的地图:

Map<String, Integer> m = new HashMap<String, Integer>();

然后您可以执行以下操作来迭代地图元素。

// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext())
    Entry<String, Integer> pair = me.next();
    System.out.println(pair.getKey() + ":" + pair.getValue());


// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet())
    System.out.println(me.getKey() + " : " + me.getValue());


// *********** Using keySet *****************************
for(String s : m.keySet())
    System.out.println(s + " : " + m.get(s));


// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext())
    String key = me.next();
    System.out.println(key + " : " + m.get(key));

【讨论】:

【参考方案24】:

这是一个通用的类型安全方法,可以调用它来转储任何给定的Map

import java.util.Iterator;
import java.util.Map;

public class MapUtils 
    static interface ItemCallback<K, V> 
        void handler(K key, V value, Map<K, V> map);
    

    public static <K, V> void forEach(Map<K, V> map, ItemCallback<K, V> callback) 
        Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();

        while (it.hasNext()) 
            Map.Entry<K, V> entry = it.next();

            callback.handler(entry.getKey(), entry.getValue(), map);
        
    

    public static <K, V> void printMap(Map<K, V> map) 
        forEach(map, new ItemCallback<K, V>() 
            @Override
            public void handler(K key, V value, Map<K, V> map) 
                System.out.println(key + " = " + value);
            
        );
    

示例

这是一个使用示例。注意Map的类型是由方法推断出来的。

import java.util.*;

public class MapPrinter 
    public static void main(String[] args) 
        List<Map<?, ?>> maps = new ArrayList<Map<?, ?>>() 
            private static final long serialVersionUID = 1L;
            
                add(new LinkedHashMap<String, Integer>() 
                    private static final long serialVersionUID = 1L;
                    
                        put("One", 0);
                        put("Two", 1);
                        put("Three", 3);
                    
                );

                add(new LinkedHashMap<String, Object>() 
                    private static final long serialVersionUID = 1L;
                    
                        put("Object", new Object());
                        put("Integer", new Integer(0));
                        put("Double", new Double(0.0));
                    
                );
            
        ;

        for (Map<?, ?> map : maps) 
            MapUtils.printMap(map);
            System.out.println();
        
    

输出

One = 0
Two = 1
Three = 3

Object = java.lang.Object@15db9742
Integer = 0
Double = 0.0

【讨论】:

【参考方案25】:

是的,许多人都认为这是迭代 Map 的最佳方式。

但是如果地图是null,就有机会抛出nullpointerexception。不要忘记输入null .check in。

                                                 |
                                                 |
                                         - - - -
                                       |
                                       |
for (Map.Entry<String, Object> entry : map.entrySet()) 
    String key = entry.getKey();
    Object value = entry.getValue();

【讨论】:

【参考方案26】:

是的,顺序取决于具体的 Map 实现。

@ScArcher2 has the more elegant Java 1.5 syntax。在 1.4 中,我会这样做:

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

【讨论】:

更喜欢 for-loop 而不是 while.. for(Iterator entries = myMap.entrySet().iterator(); entries.hasNext(); ) ... 使用这种语法,'entries'范围缩小到仅 for 循环。 @jpredham 你是对的,使用for 构造作为for (Entry e : myMap.entrySet) 将不允许你修改集合,但是@HanuAthena 提到的例子应该可以工作,因为它给了你@ 987654325@ 在范围内。 (除非我遗漏了什么……) IntelliJ 在Entry thisEntry = (Entry) entries.next(); 上给我错误:无法识别Entry。那是别的东西的伪代码吗? @JohnK 尝试导入java.util.Map.Entry 如果您有整数键和字符串键,此解决方案将不起作用。【参考方案27】:

Java 8:

您可以使用 lambda 表达式:

myMap.entrySet().stream().forEach((entry) -> 
    Object currentKey = entry.getKey();
    Object currentValue = entry.getValue();
);

更多信息,请关注this。

【讨论】:

@injecteer:似乎是 lambda 表达式的动机 如果您只想遍历地图,则不需要流。 myMap.forEach( (currentKey,currentValue) -&gt; /* action */ ); 更简洁。【参考方案28】:

理论上,最有效的方法将取决于 Map 的实现。官方的做法是调用map.entrySet(),它返回一组Map.Entry,每个都包含一个键和一个值(entry.getKey()entry.getValue())。

在一个特殊的实现中,使用map.keySet()map.entrySet() 或其他东西可能会有所不同。但我想不出为什么有人会这样写。很可能它对你所做的事情没有影响。

是的,顺序将取决于实现 - 以及(可能)插入顺序和其他难以控制的因素。

[edit] 我最初写了valueSet(),但当然entrySet()实际上是答案。

【讨论】:

【参考方案29】:
package com.test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test 

    public static void main(String[] args) 
        Map<String, String> map = new HashMap<String, String>();
        map.put("ram", "ayodhya");
        map.put("krishan", "mathura");
        map.put("shiv", "kailash");

        System.out.println("********* Keys *********");
        Set<String> keys = map.keySet();
        for (String key : keys) 
            System.out.println(key);
        

        System.out.println("********* Values *********");
        Collection<String> values = map.values();
        for (String value : values) 
            System.out.println(value);
        

        System.out.println("***** Keys and Values (Using for each loop) *****");
        for (Map.Entry<String, String> entry : map.entrySet()) 
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        

        System.out.println("***** Keys and Values (Using while loop) *****");
        Iterator<Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) 
            Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
                    .next();
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        

        System.out
                .println("** Keys and Values (Using java 8 using lambdas )***");
        map.forEach((k, v) -> System.out
                .println("Key: " + k + "\t value: " + v));
    

【讨论】:

【参考方案30】:

在 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.entrySet().stream() docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html 返回的条目使用流API 如果您想从 forEach() 中引用在 lambda 表达式之外声明的非最终变量,这将不起作用... @Chris 正确。如果您尝试从 lambda 外部使用 有效的非最终变量,它将无法工作。

以上是关于如何有效地迭代 Java Map 中的每个条目?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据非常大的df中的名称有效地将唯一ID分配给具有多个条目的个人

将 SWIG 与 C++ 的 std::map 一起使用时,Java 没有迭代器

有效擦除 tr1::unordered_map 中的元素

在比较列表中的元素时,如何有效地迭代并提高 O(n^2) 的时间复杂度?

std::map 可以在迭代器处有效地拆分为两个 std::maps 吗?

如何有效地找到从每个值到下一个较低/较高值的距离?