一位同事今天发出了一个提示,指出后一段代码更有效率,因为它不必像前者那样在每次迭代中在地图中进行查找(#1)。
#2(后者)如何更有效率?我只是不明白#1和#2是如何不同的。
**#1 snippet**
:
for (String key : map.keySet())
{
String value = map.get(key); // does lookup for every key
// do something with value
}
**#2 snippet**
:
for (Map.Entry<String, String> entry : map.entrySet())
{
String key = entry.getKey();
String value = entry.getValue();
}
答案 0 :(得分:10)
问题是map.get
通常具有显着的常数因子成本,而迭代map.entrySet()
通常与迭代map.keySet()
一样便宜。
对于像TreeMap
这样的事情来说,这是最重要的,其中第一个循环实际上是O(n log n),第二个循环是O(n),但即使对于HashMap
,{ {1}}具有可以通过第二个循环避免的常数因子成本。
答案 1 :(得分:1)
Snippet#2可以更快,因为循环的内部部分基本上是两次获取属性的调用。
在代码段#1中,在每个迭代步骤中,如果您有map.get
的错误哈希码,则调用O(n)
这是最坏情况的key
操作。即使使用良好的哈希码,找到正确的存储桶并检索value
也会产生不变的成本。
请注意,两个版本的HashMaps迭代情况相同,因为它们都使用HashIterator
:
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}