迭代键集与迭代条目集

时间:2015-01-05 18:54:18

标签: java

一位同事今天发出了一个提示,指出后一段代码更有效率,因为它不必像前者那样在每次迭代中在地图中进行查找(#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();
}

2 个答案:

答案 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(); }
}