1.两种遍历方式:
第一种:
Iterator keySetIterator = keySetMap.keySet().iterator();
while (keySetIterator.hasNext()) {
String key = keySetIterator.next();
String value = keySetMap.get(key);
// System.out.println("key:="+key+" ,value:="+value);
// System.out.println(value);
}
第二种:
Iterator> entryKeyIterator = entrySetMap.entrySet().iterator();
while (entryKeyIterator.hasNext()) {
Entry e = entryKeyIterator.next();
// System.out.println("key:="+e.getKey()+" ,value:="+e.getValue());
// System.out.println(e.getValue());
}
性能比较:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
/**
* @author Administrator
*
*/
public class testHashMap1 {
public static void Test(){
HashMap keySetMap = new HashMap();
HashMap entrySetMap = new HashMap();
/**
*
i=9000000
keyset spent times:313
entrySet spent times:169
i=4000000
keyset spent times:191
entrySet spent times:111
i=9999999
keyset spent times:400
entrySet spent times:342
* */
for (int i = 0; i < 9999999; i++) {
keySetMap.put("" + i, "keySet");
}
for (int i = 0; i < 9999999; i++) {
entrySetMap.put("" + i, "entrySet");
}
long startTimeOne = System.currentTimeMillis();
Iterator keySetIterator = keySetMap.keySet().iterator();
while (keySetIterator.hasNext()) {
String key = keySetIterator.next();
String value = keySetMap.get(key);
// System.out.println("key:="+key+" ,value:="+value);
// System.out.println(value);
}
System.out.println("keyset spent times:"
+ (System.currentTimeMillis() - startTimeOne));
long startTimeTwo = System.currentTimeMillis();
Iterator> entryKeyIterator = entrySetMap
.entrySet().iterator();
while (entryKeyIterator.hasNext()) {
Entry e = entryKeyIterator.next();
// System.out.println("key:="+e.getKey()+" ,value:="+e.getValue());
// System.out.println(e.getValue());
}
System.out.println("entrySet spent times:"
+ (System.currentTimeMillis() - startTimeTwo));
}
/**
* @param args
*/
public static void main(String[] args) {
Test();
}
}
通过测试发现,第二种方式的性能通常要比第一种方式高一倍.
2.原因分析(jdk1.8)
调用keySetMap.keySet()时执行的源代码是返回一个KeyIterator迭代器,其next方法只返回其key值.
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
而调用entrySetMap.entrySet()方法会生成EntryIterator 迭代器,其next方法返回一个Entry对象的一个实例,其中包含key和value.
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry next() { return nextNode(); }
}
二者在此时的性能应该是相同的,但方式一再取得key所对应的value时,此时还要访问Map的这个方法,这时,方式一多遍历了一次
hashmap。
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
*
* More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code (key==null ? k==null :
* key.equals(k))}, then this method returns {@code v}; otherwise
* it returns {@code null}. (There can be at most one such mapping.)
*
*
A return value of {@code null} does not necessarily
* indicate that the map contains no mapping for the key; it's also
* possible that the map explicitly maps the key to {@code null}.
* The {@link #containsKey containsKey} operation may be used to
* distinguish these two cases.
*
* @see #put(Object, Object)
*/
public V get(Object key) {
Node e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
/**
* Implements Map.get and related methods
*
* @param hash hash for key
* @param key the key
* @return the node, or null if none
*/
final Node getNode(int hash, Object key) {
Node[] tab; Node first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
这个 String value = keySetMap.get(key); 的get方法就是二者性能差别的主要原因,重新调用了do ..while循环遍历了一遍hashmap.