Possible Duplicate:
How to efficiently iterate over each entry in a 'Map'?
迭代HashMap中的项目的最佳方法是什么?
- 我需要获取键和值并将它们添加到多维数组中
- 这个问题怎么比它的复制品有更高的分数?
- 在Java 8中使用lambda表达式:StaskOfFult.COM/A/25616206/1538 59
- @不兼容性可能是因为很多人在不考虑其他映射实现的情况下本能地使用哈希映射。然后,当他们不可避免地被困在迭代哈希图的过程中时,他们会将"迭代哈希图"输入Google,引导他们直接到达这里。
- 检查答案:stackoverflow.com/a/53497541/5756557
如果您只对这些键感兴趣,那么可以遍历映射的keySet():
1 2 3 4 5
| Map <String, Object > map = ... ;
for (String key : map. keySet()) {
// ...
} |
如果只需要这些值,请使用values():
1 2 3
| for (Object value : map. values()) {
// ...
} |
最后,如果您同时需要键和值,请使用entrySet():
1 2 3 4 5
| for (Map. Entry<String, Object > entry : map. entrySet()) {
String key = entry. getKey();
Object value = entry. getValue();
// ...
} |
一个警告:如果你想在迭代过程中删除项目,你需要通过一个迭代器来完成(参见Karim79的答案)。但是,更改项目值是可以的(参见Map.Entry)。
- 那么如何同时循环两个映射呢?使用entryset方法?我尝试过使用,但它不起作用
- 使用两个迭代器。请参阅接受的答案,例如迭代器的用法。
- 只有当您同时需要键和值时,才更有效地使用entryset。如果您只需要一个或另一个,那么只需使用那个:stackoverflow.com/questions/3870064/&hellip;
- 还有一个更重要的点,keyset()返回的集合和values()返回的集合都由原始映射支持。也就是说,如果对它们进行任何修改,它们将反映在映射中,但是,它们都不支持add()和addall()方法,即不能向集合中的集合或新值添加新键。
- 关于获取值和键,使用第一个foreach示例并在循环中获取值不仅简单,而且使用value = map.get(key)?entrySet的性能是否更高?
- @Marcosulla这样的性能问题取决于你,你应该在重要的情况下衡量和观察。使用entrySet可能更快,因为它可以避免对每个条目进行查找。具体的Map的实现决定了哪种方式更好,并且取决于多少。此时的GC压力也可能是一个因素。
- 既然map不属于迭代器类,那么在第一个解决方案中,这个人是如何使用迭代器的?
- "map.entry entry"和"map.entryentry"的类型错误为"必需的对象,找到的项"。我正在将整数映射到哈希映射。因此,必须使用keyset for循环,并通过'value=(hashmap)integertomap.get(key)'(value=(hashmap)获取该值,但如果我可以使用entryset而不使用迭代器,则效率会更低,如您的示例所示。
像这样迭代entrySet():
1 2 3 4 5 6 7 8
| 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
}
} |
了解更多关于Map的信息。
- 虽然是旧样式,但这将有助于避免下面答案中新的foreach样式的并发修改例外。例如,可以通过单独的迭代器删除。
- @卡里姆79您对以下方式有何看法:Map map = new HashMap(); for (Map.Entry entry : map.entrySet()) { System.out.println("Key =" + entry.getKey() +", Value =" + entry.getValue()); }。
- 通过调用"it.remove();"您将清空映射,使其在该映射是类变量时不可重用。你有什么解决办法吗?
- @Vimukthi你说的解决方法是什么?只需拆下it.remove();线即可。
- for (Map.Entry cursor : map.entrySet()) {...}语法更好。
- 在调用remove()和不调用remove()两种语法之间,并发修改异常的可能性有什么不同吗?有些答案暗示着矛盾的断言(第一句和第四句评论)
- 迭代器接口是自1.2以来的通用接口。它必须是迭代器
- 我认为arvnid的答案,尽管只是一个复制/粘贴或不是。(我同意给予属于自己的人适当的荣誉是合乎道德的)
- 我不小心落在这里,我们为什么要在这里做Iterator.remove()?OP刚刚要求一种迭代Map的最佳方法。
- 请注意,it.remove不适用于不可修改的映射,如system.getenv()返回字符串映射。
- 迭代器的完整类型是:import java.util.迭代器;
- @哈托的答案是更好的,因为它告诉读者如何在各种情况下实际使用它。您的解决方案的应用范围很小。非常小。
- 是否不使用"lineHile(it.hasNext())"跳过第一个条目?
- 所以大局的步骤似乎是1。使用entryset 2转换为集合。把它变成一个迭代器和3。调用hasNext并将每个下一个对象转换为map.entry对象?
- 每个人都说for (Map.Entry cursor : map.entrySet())比这更好,这忽略了这样一个事实,即使用该方法仍将收到ConcurrentModificationException。所选的答案仍然是遍历Map的最佳方法。
- @ J&A 252;RGENK。不,it.hasNext()返回一个布尔值,该值基于迭代器是否有当前元素之外的另一个元素,但没有提升迭代器的状态。在调用it.next()之前,迭代器不会被提升到下一个元素。
- @亚历克斯是的,我也是。
- @ashishduh所选的答案仅在需要在迭代期间修改映射的特殊情况下才是最好的。对于所有其他用途,最好使用增强的for循环。
- 这个API是不直观的,所以我反复谷歌这个答案,并在这个答案上至少20次!!
- 事实上,Java 1.2引入迭代器,但那时没有泛型。仅在1.5中添加了仿制药。
- 请不要再使用迭代器。
- 我得到'(map.entry)it.next()'的未选中强制转换和未选中分配警告。我添加了一个检查到map,entry:'map.entryentry'以避免其他问题。
- 由于map不在迭代器类下,如何在map中使用迭代器?只有列表、队列和集合是不可更改的。
- 也许为Java 8更新这个?(例如,提供两个版本,一个用于Java 8之前,一个版本仅用于Java 8)。
- ConcurrentHashMap是ConcurrentMap接口的实现。Concurrentmap接口扩展了映射接口。混淆是因为这个问题是专门针对hashmap提出的。hashmap是映射接口的实现。最好声明一个concurrenthashmap,如:mapmymap=new concurrenthashmap();而不是:concurrenthashmapmymap=new concurrenthashmap();第一个实践允许扩展性。这就是为什么这是一个成熟的答案。
- 我认为这个回答不好。OP只要求遍历映射,而不是在迭代期间如何修改映射。
从引用中提取如何在Java中遍历地图:
在Java中迭代EDCOX1的1种方法有几种方式。让我们回顾一下最常用的方法,回顾一下它们的优缺点。由于Java中的所有映射都实现了MAP接口,下面的技术将用于任何映射实现(EDCOX1,12,EDCOX1,13,EDCOX1,14,EDCOX1,15,等等)。
方法1:使用for each循环迭代条目。
这是最常见的方法,在大多数情况下更可取。如果循环中同时需要映射键和值,则应该使用它。
1 2 3 4
| 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());
} |
注意,每个循环都是在Java 5中引入的,所以这种方法只适用于新版本的语言。另外,如果您试图在一个为空的映射上迭代,for-each循环将抛出NullPointerException,因此在迭代之前,您应该始终检查是否有空引用。
方法2:使用for each循环迭代键或值。
如果只需要映射中的键或值,则可以迭代键集或值,而不是EntrySet。
1 2 3 4 5 6 7 8 9 10 11
| 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 );
} |
该方法比entrySet迭代(大约快10%)稍有性能优势,而且更干净。
方法3:使用迭代器迭代。
使用泛型:
1 2 3 4 5 6
| 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());
} |
无仿制药:
您还可以使用相同的技术对keySet或值进行迭代。
这种方法看起来可能是多余的,但它有自己的优点。首先,它是在旧版本的Java中迭代地图的唯一方法。另一个重要特性是,它是唯一允许您在迭代期间通过调用iterator.remove()从映射中删除条目的方法。根据JavaDoc,如果在每次迭代中尝试这样做,将得到"不可预知的结果"。
从性能的角度来看,这个方法在每次迭代中等于。
方法4:迭代键并搜索值(效率低下)。
1 2 3 4 5
| 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,这可能看起来是一种更清洁的替代方法,但实际上,它非常缓慢且效率低下,因为通过键获取值可能很耗时(在不同的映射实现中,此方法比方法1慢20%-200%)。如果安装了findbugs,它将检测到这一点并警告您迭代效率低下。应避免使用这种方法。
结论:
如果只需要映射中的键或值,请使用方法2。如果你坚持旧版本的Java(小于5)或者计划在迭代过程中删除条目,则必须使用方法3。否则使用方法1。
- 让我们添加一个小的caevet,在ConcurrentMaps的情况下,keySet()上的迭代通常会崩溃(不能保证先前收集的密钥的值存在)。另一方面,使用迭代器或条目是安全的(它们总是引用现有的对象)。
- @Arvind,方法4的效率如何?根据定义,对于散列映射,调用get()总是O(1)。这是散列映射的定义,用户请求散列映射。我不明白为什么这是如此高的赞成票。如果你要引用别人的链接,请确保它对所问的问题是有意义的。
- @Ohbrobig是O(1),但这是运行时,这就是它的扩展方式。这并不意味着它在第一个周期中必然得到值。方法4肯定比方法1慢。
1 2 3 4
| for (Map. Entry<String, String > item : hashMap. entrySet()) {
String key = item. getKey();
String value = item. getValue();
} |
- param是哈希图的名称吗?
- @Chanjungkim是的,它是hashmap的名字
您可以用多种方式迭代Map中的条目。获取每个键和值,如下所示:
1 2 3 4 5
| Map <?, ?> map = new HashMap <Object, Object >();
for(Entry <?, ?> e : map. entrySet()){
System. out. println("Key" + e. getKey());
System. out. println("Value" + e. getValue());
} |
或者你可以用
1 2 3 4 5
| Collection <?> keys = map. keySet();
for(Object key : keys ){
System. out. println("Key" + key );
System. out. println("Value" + map. get(key ));
} |
如果您只想获取所有的值,而不关心这些键,那么可以使用:
1
| Collection<?> values = map.values(); |
更聪明的:
1 2 3
| for (String key : hashMap. keySet()) {
System. out. println("Key:" + key +", Value:" + map. get(key ));
} |
- 这实际上取决于你是否需要钥匙。如果没有,则使用entryset()作为hashcode()不被调用更有效。
- 每次迭代的map.get(key)不是更聪明——它的速度慢了很多。
- map.entryset()返回已经包含键和值的项。这样就不必在迭代期间调用hashcode()并搜索哈希。
- Java 8语法。可能仍然不适用于Android开发。"Android并不是100%兼容任何Java SE API版本,而不是6或8也不兼容。…JRE是Java运行时环境,而JDK是Java开发工具包。它是Android应用程序开发所需的JDK以及现有的Android SDK。
视情况而定。如果您知道您将需要每个条目的键和值,那么就通过entrySet。如果您只需要这些值,那么这里有values()方法。如果你只需要钥匙,那就用keySet()。
一个糟糕的做法是遍历所有键,然后在循环中,总是执行map.get(key)来获取值。如果你这样做,那么我写的第一个选择就是为你。
- 还有一个更重要的点,keyset()返回的集合和values()返回的集合都由原始映射支持。也就是说,如果对它们进行任何修改,它们将反映在映射中,但是,它们都不支持add()和addall()方法,即不能向集合中的集合或新值添加新键。