我们在写程序时,一般要用到key-value时喜欢用HashMap来保存数据,当我们要取数据的时候我们就会用到iterator(迭代器),目前有两种比较常用的方法来取数据:
1)
<span style="white-space:pre"> </span>Map map = new HashMap(); Iterator iterator = map.entrySet().iterator(); if(iterator.hasNext()){ Map.Entry entry = (Entry) iterator.next(); Object key = entry.getKey(); Object value = entry.getValue(); }
2)
<span style="white-space:pre"> </span>Map map = new HashMap(); Iterator iterator = map.keySet().iterator(); if(iterator.hasNext()){ Object key = iterator.next(); Object value = map.get(key); }
下面我们通过源代码来看一下这两种方法的区别:
首先我们先看一下第一种方法的源代码:
map.entrySet():
public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es; return (es = entrySet) == null ? (entrySet = new EntrySet()) : es; }
再来看一下entrySet.iterator()
final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator<Map.Entry<K,V>> iterator() { return new EntryIterator(); }..... }返回的是new EntryIterator()
final class EntryIterator extends HashIterator implements Iterator<Map.Entry<K,V>> { public final Map.Entry<K,V> next() { return nextNode(); } }
final Node<K,V> nextNode() { Node<K,V>[] t; Node<K,V> e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); <span style="color:#ff0000;">if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null); }</span> return e; }
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; }.... }可以看出 Node<K,V>继承Map.Entry<K,V>,Node的构造方法里包含了key和value
在来看看第二个方法:
map.keySet():
public Set<K> keySet() { Set<K> ks; return (ks = keySet) == null ? (keySet = new KeySet()) : ks; }
可以看出keySet是通过KeyySet空的构造方法来的
再来看一下keySet.iterator()
final class KeySet extends AbstractSet<K> { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator<K> iterator() { return new KeyIterator(); }.... }返回的是new KeyIterator()
final class KeyIterator extends HashIterator implements Iterator<K> { public final K next() { return nextNode().key; } }nextNode()和上面的一样,只是这里返回的是Node中的key
方法一中:iterator.next()返回的是Map.Entry()类型,而且Map.Entry()中包含了key和value
方法二中:iterator.next()返回的是key,需要通过map.get(key)来获得value
见map.get(key)源码
public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }再来看getNode()
final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> 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<K,V>)first).getTreeNode(hash, key); <span style="color:#ff0000;">do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null);</span> } } return null; }其中红色的是遍历的逻辑代码
综上所述,可以看出,方法一中遍历了一次,把key和value放到了entry中
方法二中遍历了两次,一次是遍历了iterator,一次是用key从map中取出value
所以,我们在利用iterator遍历hashMap集合时,利用方法一比方法二更快一些。