java集合 - 地图中的keyset()与entrySet()
Posted
技术标签:
【中文标题】java集合 - 地图中的keyset()与entrySet()【英文标题】:java collections - keyset() vs entrySet() in map 【发布时间】:2012-02-16 06:15:49 【问题描述】:我把一个字符串数组元素是一个映射,其中字符串数组的元素是键,单词的频率是值,例如:
String[] args = "if","it","is","to","be","it","is","up","me","to","delegate";
那么地图就会有类似[ if:1, it:2 .... ]
的条目
Set<String> keys = m.keySet();
System.out.println("keyset of the map : "+keys);
打印所有键:"if","it","is","to","be","it","is","up","me","to","delegate"
Set<Map.Entry<String, Integer>> entrySet = m.entrySet();
Iterator<Map.Entry<String, Integer>> i = entrySet.iterator();
while(i.hasNext())
Map.Entry<String, Integer> element = i.next();
System.out.println("Key: "+element.getKey()+" ,value: "+element.getValue());
打印所有键值对:
使用条目集打印所有值:
Key: if ,value: 1
Key: it ,value: 2
Key: is ,value: 2
Key: to ,value: 2
Key: be ,value: 1
Key: up ,value: 1
Key: me ,value: 1
Key: delegate ,value: 1
但下面的代码块应该打印与上面完全相同的输出,但它没有:
Iterator<String> itr2 = keys.iterator();
while(itr2.hasNext())
//System.out.println(itr1.next()+" ");
//System.out.println(m.get(itr1.next())+" ");
System.out.println("Key: "+itr2.next()+" ,value: "+m.get(itr2.next()));
打印出来:
Key: if ,value: 2
Key: is ,value: 2
Key: be ,value: 1
Key: me ,value: 1
但是如果我们在 while 循环中取消注释第 1 行,即
System.out.println(itr1.next()+" ");
并注释该行
System.out.println("Key: "+itr2.next()+" ,value: "+m.get(itr2.next()));
然后我们得到所有密钥:"if","it","is","to","be","it","is","up","me","to","delegate";
如果我们使用m.get()
和itr2.next()
,那么迭代器不会有几个键!
【问题讨论】:
如果你要存储很多整数值,你应该查看 fastutil 库而不是 j.u 集合。 键集不会有重复,我猜它不应该将“it”字符串打印两次。在此调用 Set为简单起见,请注意,每次您执行itr2.next()
时,指针都会移动到下一个元素,即此处,如果您仔细注意,那么根据您编写的逻辑,输出是完全正常的。
这可能有助于您更好地理解:
While 循环的第一次迭代(指针在第一个元素之前):
键:如果,值:2 itr2.next()=if; m.get(itr2.next()=it)=>2
While 循环的第二次迭代(指针在第三个元素之前):
键:是,值:2 itr2.next()=is; m.get(itr2.next()=to)=>2
While 循环的第 3 次迭代(指针在第 5 个元素之前):
键:be ,值:1 itr2.next()="be"; m.get(itr2.next()="up")=>"1"
While 循环的第 4 次迭代(指针在第 7 个元素之前):
键:我,值:1 itr2.next()="me"; m.get(itr2.next()="delegate")=>"1"
键:如果,值:1 键:它,值:2 键:是,值:2 键:到,值:2 键:是,值:1 键:向上,值:1 键:我,值:1 键:委托,值:1
打印出来:
键:如果,值:2 键:是,值:2 键:是,值:1 键:我,值:1
【讨论】:
【参考方案2】:遍历大地图entrySet()
比keySet()
好得多。查看this 教程他们如何在entrySet(
的帮助下优化对大对象的遍历以及它如何有助于性能调整。
【讨论】:
【参考方案3】:Iterator
只会向前移动,如果它读取一次,就完成了。你的
m.get(itr2.next());
正在读取itr2.next();
的下一个值,这就是为什么您缺少几个(实际上不是几个,每隔一个)键。
【讨论】:
【参考方案4】:每次调用Iterator.next()
都会将迭代器移动到下一个元素。如果要在多个语句或表达式中使用当前元素,则必须将其存储在局部变量中。或者更好的是,为什么不简单地使用 for-each 循环?
for (String key : map.keySet())
System.out.println(key + ":" + map.get(key));
此外,遍历 entrySet 更快,因为您不会为每个键查询两次映射。另外Map.Entry
实现通常实现toString()
方法,因此您不必手动打印键值对。
for (Entry<String, Integer> entry : map.entrySet())
System.out.println(entry);
【讨论】:
感谢您提到这一点非常重要:使用条目集来避免调用get()
的不必要开销。
“因为你没有为每个键查询两次地图”为什么两次?我以为你在做 map.get(key) 时只查询一次?
@HenryNguyen 我相信他的意思是你在使用迭代器获取密钥时查询它一次【参考方案5】:
每次调用 itr2.next() 时,都会得到一个不同的值。值不一样。您应该只在循环中调用一次。
Iterator<String> itr2 = keys.iterator();
while(itr2.hasNext())
String v = itr2.next();
System.out.println("Key: "+v+" ,value: "+m.get(v));
【讨论】:
在 Effective Java 书中提到了同样的错误,这就是为什么使用 foreach 循环是首选的原因。 很幸运,您的地图中有偶数个条目,否则您会遇到 RuntimeException +1 对阿米尔的评论。除非您需要从集合中移除项目,否则直接使用 Iterator 只会引入出错的可能性。对于简单的读取循环,您应该使用 foreach 循环样式。以上是关于java集合 - 地图中的keyset()与entrySet()的主要内容,如果未能解决你的问题,请参考以下文章
Map集合中value()方法与keySet()entrySet()区别