HashMap遍历--entrySet()与keySet()比较

我们在写程序时,一般要用到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是通过EnteySet空的构造方法来的

再来看一下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(); }
    }

再来看一下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;
        }

红色标记的就是该方法的遍历代码,返回的是Node<K,V>类型,再来看看 Node<K,V>
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集合时,利用方法一比方法二更快一些。





你可能感兴趣的:(HashMap,遍历,迭代器)