Java中遍历HashMap对象中的条目(Entry)时,通常有两种方式:
- 通过KeySet遍历
- 通过EntrySet遍历
下面的测试分别采用KeySet和EntrySet,通过forEach遍历同一个HashMap对象中的条目。
测试结果表明,方法2通过EntrySet遍历效率优于方法1通过KeySet遍历。
Java代码:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestMapTraversal {
private static int MAXCOUNT = 3000000;
private static Map<Integer, Integer> map = new HashMap<>();
@BeforeClass
public static void initMap() {
for (int i = 0; i < MAXCOUNT; i++) {
map.put(i, i + 1);
}
}
@Test
public void testEntrySet() {
int sum = 0;
for (Entry<Integer, Integer> e : map.entrySet()) {
sum += e.getKey() ^ e.getValue();
}
System.out.println(sum);
}
@Test
public void testKeySet() {
int sum = 0;
for (Integer key : map.keySet()) {
sum += key ^ map.get(key);
}
System.out.println(sum);
}
}
阅读HashMap的源码,对比内部类KeySet和EntrySet中forEach方法的实现。
HashMap.KeySet
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
HashMap.EntrySet
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
实际上两种遍历方式都是对HashMap中的table属性进行遍历,而通过KeySet获取到key之后还需要再次调用get方法,所以效率要差一些。
本文链接:http://bookshadow.com/weblog/2016/10/12/how-to-efficiently-traverse-each-entry-in-java-hashmap/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。