遍历 HashMap [duplicate]

Iterate through a HashMap [duplicate]

提问人:burntsugar 提问时间:7/1/2009 最后编辑:S.S. Anneburntsugar 更新时间:9/26/2022 访问量:4415944

问:

迭代 HashMap 中项目的最佳方式是什么?

Java 循环 哈希图 迭代

评论

7赞 burntsugar 7/1/2009
我需要获取键和值并将它们添加到多维数组中
8赞 Nitin Mahesh 7/26/2015
在 Java 8 中使用 Lambda 表达式: stackoverflow.com/a/25616206/1503859

答:

3451赞 karim79 7/1/2009 #1

像这样遍历 entrySet():

public static void printMap(Map mp) {
    Iterator it = mp.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pair = (Map.Entry)it.next();
        System.out.println(pair.getKey() + " = " + pair.getValue());
        it.remove(); // avoids a ConcurrentModificationException
    }
}

阅读有关地图的更多信息。

评论

40赞 Benjamin Wootton 12/16/2010
虽然是旧样式,但这将有助于避免 ConcurrentModificationExceptions 在下面的答案中采用新的 foreach 样式。例如,您可以通过单独的迭代器删除。
471赞 fresh_dev 10/25/2011
@karim79您如何看待以下方式:Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); }
15赞 vim 1/10/2012
通过调用 'it.remove();' 您正在清空映射,如果此映射是类变量,则使其不可重用。你有什么解决方案吗?
28赞 Danny 1/27/2012
@vimukthi你说的解决方案是什么?只需删除该行即可。it.remove();
114赞 Chad Okere 1/29/2012
for 语法要好得多。(Map.Entry<String, Object> cursor : map.entrySet()) {...}
5372赞 harto 7/1/2009 #2

如果你只对键感兴趣,你可以遍历映射的 keySet():

Map<String, Object> map = ...;

for (String key : map.keySet()) {
    // ...
}

如果只需要这些值,请使用 values()

for (Object value : map.values()) {
    // ...
}

最后,如果你同时需要键和值,请使用 entrySet()

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

需要注意的是:如果你想在迭代过程中删除项目,你需要通过迭代器来完成(参见 karim79 的回答)。但是,更改项目值是可以的(请参阅 Map.Entry)。

评论

3赞 DaMainBoss 7/27/2011
那么如何同时循环遍历 2 张地图呢?使用 entrySet 方法?我尝试使用&&,但它可以工作
2赞 harto 7/27/2011
使用两个迭代器。有关迭代器的示例用法,请参阅接受的答案。
21赞 rogerdpack 10/6/2011
只有在需要键和值时,使用 entrySet 才会更有效。如果您只需要一个或另一个,那么只需使用那个:stackoverflow.com/questions/3870064/......
4赞 sactiw 1/24/2014
还有一点很重要,keySet() 返回的 Set 和 values() 返回的 Collection 都由原始 Map 支持。也就是说,如果你对它们进行任何修改,它们将反映回 Map 中,但是,它们都不支持 add() 和 addAll() 方法,即你不能向 Set 添加新键或在 Collection 中添加新值。
0赞 Marco Sulla 4/18/2017
关于获取值和键,使用第一个示例并在循环中获取值不仅更简单,使用 ?性能是不是更高?foreachvalue = map.get(key)entrySet
56赞 Gary Kephart 7/1/2009 #3

这要视情况而定。如果您知道将需要每个条目的键和值,则通过 .如果你只需要这些值,那么就有了方法。如果您只需要密钥,请使用 .entrySetvalues()keyset()

一个不好的做法是遍历所有键,然后在循环中,始终这样做来获取值。如果你这样做,那么我写的第一个选项就是为你准备的。map.get(key)

评论

1赞 sactiw 1/24/2014
还有一点很重要,keySet() 返回的 Set 和 values() 返回的 Collection 都由原始 Map 支持。也就是说,如果你对它们进行任何修改,它们将反映回 Map 中,但是,它们都不支持 add() 和 addAll() 方法,即你不能向 Set 添加新键或在 Collection 中添加新值。
107赞 codethulhu 7/1/2009 #4

您可以通过多种方式遍历 Map 中的条目。像这样获取每个键和值:

Map<?,?> map = new HashMap<Object, Object>();
for(Entry<?, ?> e: map.entrySet()){
    System.out.println("Key " + e.getKey());
    System.out.println("Value " + e.getValue());
}

或者你可以通过以下命令获取密钥列表

Collection<?> keys = map.keySet();
for(Object key: keys){
    System.out.println("Key " + key);
    System.out.println("Value " + map.get(key));
}

如果您只想获取所有值,而不关心键,则可以使用:

Collection<?> values = map.values();
76赞 jkarretero 8/11/2010 #5

聪明:

for (String key : hashMap.keySet()) {
    System.out.println("Key: " + key + ", Value: " + map.get(key));
}

评论

10赞 icfantv 10/6/2011
这实际上取决于您是否需要密钥。如果没有,使用 entrySet() 会更有效,因为 hashCode() 不会被调用。
17赞 CompEng88 4/19/2013
map.get(key) 并不是更聪明 -- 它的方式更慢
2赞 CompEng88 4/16/2016
map.entrySet(),它返回已经包含键和值的条目。这样,您就不必在迭代期间调用 hashCode() 并搜索哈希值。
0赞 jasonleonhard 8/6/2017
Java 8 语法。可能仍然不适用于 Android 开发。“Android 并非旨在与任何 Java SE API 版本100% 兼容,而不是 6、8 或任何版本。...JRE 是 Java 运行时环境,而 JDK 是 Java 开发工具包。它是 Android 应用程序开发所需的 JDK 以及现有的 Android SDK。2013 年 12 月 9 日“来源
184赞 gabor 7/23/2011 #6
for (Map.Entry<String, String> item : hashMap.entrySet()) {
    String key = item.getKey();
    String value = item.getValue();
}
873赞 arvind 12/8/2011 #7

摘自参考文献 How to Iterate Over a Map in Java

在 Java 中,有几种迭代方法。让我们回顾一下最常见的方法并回顾它们的优缺点。由于 Java 中的所有映射都实现了 Map 接口,因此以下技术适用于任何映射实现(、、、等)MapHashMapTreeMapLinkedHashMapHashtable

方法#1:使用For-Each循环遍历条目。

这是最常见的方法,在大多数情况下更可取。如果在循环中同时需要映射键和值,则应使用它。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

请注意,For-Each 循环是在 Java 5 中引入的,因此此方法仅适用于该语言的较新版本。此外,如果您尝试遍历 null 的映射,则会抛出 For-Each 循环,因此在迭代之前,应始终检查是否有 null 引用。NullPointerException

方法#2:使用For-Each循环遍历键或值。

如果只需要映射中的键或值,则可以循环访问 keySet 或值,而不是 entrySet。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

// Iterating over keys only
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}

// Iterating over values only
for (Integer value : map.values()) {
    System.out.println("Value = " + value);
}

与迭代相比,此方法具有轻微的性能优势(快约 10%),并且更干净。entrySet

方法#3:使用迭代器进行迭代。

使用泛型:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

不使用泛型:

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry entry = (Map.Entry) entries.next();
    Integer key = (Integer)entry.getKey();
    Integer value = (Integer)entry.getValue();
    System.out.println("Key = " + key + ", Value = " + value);
}

还可以使用相同的技术来循环访问 或 值。keySet

这种方法可能看起来多余,但它有其自身的优点。首先,这是在旧版本的 Java 中遍历映射的唯一方法。另一个重要功能是,它是唯一允许您在迭代期间通过调用 从映射中删除条目的方法。根据 Javadoc 的说法,如果你在 For-Each 迭代期间尝试这样做,你会得到“不可预测的结果”。iterator.remove()

从性能角度来看,此方法等于 For-Each 迭代。

方法#4:遍历键并搜索值(效率低下)。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key = " + key + ", Value = " + value);
}

这看起来像是方法 #1 的更简洁的替代方案,但实际上它非常缓慢且效率低下,因为通过键获取值可能很耗时(这种方法在不同的 Map 实现中比方法 #1 慢 20%-200%)。如果您安装了 FindBugs,它将检测到这一点并警告您低效的迭代。应避免使用这种方法。

结论:

如果只需要映射中的键或值,请使用方法 #2。如果您坚持使用旧版本的 Java(少于 5)或计划在迭代期间删除条目,则必须使用方法 #3。否则,请使用方法#1。

评论

1赞 P Marecki 2/29/2016
让我们添加一个小的 caevet,在 s 的情况下,迭代 on 通常会崩溃(不能保证之前收集的键存在值)。另一方面,使用迭代器或条目是安全的(它们总是引用现有对象)。ConcurrentMapkeySet()
3赞 ohbrobig 6/3/2018
@arvind 方法 #4 怎么会效率低下?根据定义,对 HashMap 的调用始终为 O(1)。这就是 HashMap 的定义,用户要求提供 HashMap。我不明白为什么这被如此高的投票。如果您要引用其他人的链接,请确保它对提出的问题确实有意义。get()
1赞 user961954 4/13/2019
@ohbrobig,它仍然是 O(1),但这是运行时,这就是它的扩展方式。这并不意味着它一定会在第一个周期中获得该值。方法#4肯定会比方法#1慢