`
kim_miao
  • 浏览: 190897 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

keySet 与entrySet 遍历HashMap性能差别

    博客分类:
  • Java
 
阅读更多
一.问题发现
今天,在写完代码后用Find Bugs扫锚了一下,发现类中一处代码中有提示如下内容:
       
Map<String, EventChain> map = ContextHolder.getContext().getEventChains();
        for (Iterator<String> iter = map.keySet().iterator(); iter.hasNext();) {
            String key = iter.next();
            EventChain eventChain = eventChains.get(key);
         }

makes inefficient use of keySet iterator instead of entrySet iterator
意思是说用keySet 方式遍历Map的性能不如entrySet性能好.起初想不明白,索性仔细看下代码:

二.常用的遍历HashMap的两种方法

1.第一种方式
Iterator<String> keySetIterator = keySetMap.keySet().iterator();
		while (keySetIterator.hasNext()) {
			String key = keySetIterator.next();
			String value = keySetMap.get(key);
			
		}



2.第二种方式
Iterator<Entry<String, String>> entryKeyIterator = entrySetMap.entrySet()
				.iterator();
		while (entryKeyIterator.hasNext()) {
			Entry<String, String> e = entryKeyIterator.next();
			String value=e.getValue();
		}


三.性能比较

    到底第二种方式的性能比第一种方式的性能高多少呢,通过一个简单的测试类可以看一下,测试代码如下:
public class HashMapTest {
	public static void main(String[] args) {

		HashMap<String, String> keySetMap = new HashMap<String, String>();
		HashMap<String, String> entrySetMap = new HashMap<String, String>();

		for (int i = 0; i < 1000; i++) {
			keySetMap.put("" + i, "keySet");
		}
		for (int i = 0; i < 1000; i++) {
			entrySetMap.put("" + i, "entrySet");
		}

		long startTimeOne = System.currentTimeMillis();
		Iterator<String> keySetIterator = keySetMap.keySet().iterator();
		while (keySetIterator.hasNext()) {
			String key = keySetIterator.next();
			String value = keySetMap.get(key);
			System.out.println(value);
		}

		System.out.println("keyset spent times:"
				+ (System.currentTimeMillis() - startTimeOne));

		long startTimeTwo = System.currentTimeMillis();

		Iterator<Entry<String, String>> entryKeyIterator = entrySetMap
				.entrySet().iterator();
		while (entryKeyIterator.hasNext()) {
			Entry<String, String> e = entryKeyIterator.next();
			System.out.println(e.getValue());
		}
		System.out.println("entrySet spent times:"
				+ (System.currentTimeMillis() - startTimeTwo));

	}
}


通过测试发现,第二种方式的性能通常要比第一种方式高一倍.

四.原因分析:

  通过查看源代码发现,调用这个方法keySetMap.keySet()会生成KeyIterator迭代器,其next方法只返回其key值.
 private class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

而调用entrySetMap.entrySet()方法会生成EntryIterator 迭代器,其next方法返回一个Entry对象的一个实例,其中包含key和value.
 private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
  }

二者在此时的性能应该是相同的,但方式一再取得key所对应的value时,此时还要访问Map的这个方法,这时,方式一多遍历了一次table.

public V get(Object key) {
        Object k = maskNull(key);
        int hash = hash(k);
        int i = indexFor(hash, table.length);
        Entry<K,V> e = table[i]; 
        while (true) {
            if (e == null)
                return null;
            if (e.hash == hash && eq(k, e.key)) 
                return e.value;
            e = e.next;
        }
    }

这个方法就是二者性能差别的主要原因.


分享到:
评论
3 楼 jzp12 2017-07-05  
while (keySetIterator.hasNext()) {  
      String key = keySetIterator.next();  
      String value = keySetMap.get(key);  
      System.out.println(value);  
}
这段代码会误导人,如果把
String value = keySetMap.get(key);  
System.out.println(value); 
合成一句System.out.println(keySetMap.get(key)); 

两种遍历方法时间几乎无差异。

2 楼 ysushiwei 2013-03-12  
差别确实不大,基本上可以忽略。
我测试的是10万的数据量级别的。
再大了,电脑内存就吃不消了。
1 楼 hhhk 2011-03-28  
在公司电脑上测试10万级别以上才会显示出优势,10万级别一下 2种遍历是差不多的

相关推荐

    Java5种遍历HashMap数据的写法

    除了使用EntrySet的迭代器,我们还可以使用KeySet的迭代器来遍历HashMap中的数据。其实现代码如下: ```java Iterator&lt;Integer&gt; iterator = coursesMap.keySet().iterator(); while (iterator.hasNext()) { Integer...

    java遍历HashMap简单的方法

    遍历HashMap是开发者经常遇到的任务,尤其在处理数据操作时。本篇文章将详细介绍如何使用简单的方法来遍历HashMap,通过实例代码帮助理解。 HashMap遍历的常用方法主要有三种:迭代器(Iterator)遍历、键集...

    基于HashMap遍历和使用方法(详解)

    3. 通过Map.entrySet遍历key和value 这是一种使用增强for循环遍历键值对的方法。 ```java for (Map.Entry, String&gt; entry : map.entrySet()) { System.out.println("key= " + entry.getKey() + " and value= " + ...

    使用多种方式实现遍历HashMap的方法

    遍历HashMap是常见的操作,本文将介绍六种不同的方法来实现这一功能。 1. **方式一:使用KeySet方法** KeySet方法返回HashMap中所有键的Set视图。由于Set接口实现了Iterable接口,我们可以使用for-each循环来遍历...

    HashMap遍历

    本文将深入探讨`HashMap`的遍历方法,包括`keySet()`和`entrySet()`两种主要方式,并通过代码示例对比它们的性能差异。 #### 方法一:使用`keySet()`遍历 `keySet()`方法返回`HashMap`中的所有键的集合视图。通过...

    怎样遍历一个HashMap?

    可以通过2种方法遍历HashMap &lt;br&gt;Map map = new HashMap(); &lt;br&gt;for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { &lt;br&gt; Map.Entry entry = (Map.Entry) iter.next(); &lt;br&gt; Object ...

    Java HashMap三种循环遍历方式及其性能对比实例分析

    这是因为它们都使用了迭代器来遍历HashMap,时间复杂度相同。for each keySet的性能较差,是因为需要再次调用get方法来获取值,增加了时间复杂度。 源码分析 通过查看HashMap的源码,可以看到entrySet()和keySet()...

    HashMap和List遍历方法及如何遍历删除元素总结

    要解决HashMap遍历删除元素的问题,可以使用Iterator来遍历HashMap,并使用Iterator的remove方法来删除元素。这样可以避免ConcurrentModificationException异常。 小结 在遍历和删除HashMap和List的元素时,需要...

    Java 实例 - HashMap遍历源代码-详细教程.zip

    - 遍历HashMap时修改HashMap(添加、删除元素)可能会导致`ConcurrentModificationException`,因为迭代器无法检测到这种并发修改。 - 使用`keySet()`遍历并删除元素是安全的,但效率较低,因为这涉及到两次查找:...

    Java HashMap的三种遍历方法及优缺点含示例

    通过entrySet()方法,我们可以遍历HashMap中的每个键值对(Entry)。这种方式不仅可以遍历到所有的键,还可以在单次遍历中直接获得与键相对应的值。对于需要同时处理键和值的场景,entrySet()是最为高效的方法。 **...

    java哈希遍历_哈希遍历_

    - 遍历HashMap时,由于内部实现细节,顺序可能不稳定,因为哈希函数可能会导致元素在数组中的顺序发生变化。如果需要稳定的遍历顺序,可以考虑使用`LinkedHashMap`,它在保持效率的同时,按照插入顺序或访问顺序遍历...

    如何得到hashmap的索引

    #### 遍历HashMap的方法 根据提供的内容,我们可以了解到遍历`HashMap`主要有两种方式:使用`keySet()`方法和使用`entrySet()`方法。 1. **使用keySet()方法** ```java Map map = new HashMap(); Iterator ...

    JAVA遍历Map所有元素.doc

    在上述的`HashMapTest`类中,通过对比`keySet()`和`entrySet()`遍历HashMap的时间,我们可以看到`entrySet()`方法通常比`keySet()`方法更快。`keySet()`需要两次遍历:一次是转换为迭代器,另一次是从HashMap中根据...

    hashmap使用实例

    6. **遍历HashMap**:有两种方式遍历HashMap,一是通过`entrySet()`获取键值对的迭代器,二是通过`keySet()`获取键的迭代器再获取对应的值。 ```java for (Map.Entry, String&gt; entry : map.entrySet()) { System....

    HashMap的数据结构

    8. **迭代器**:HashMap提供了迭代器`keySet()`、`values()`和`entrySet()`,分别用于获取键集合、值集合和键值对集合的迭代器,方便遍历HashMap的所有元素。 9. ** equals() 和 hashCode()**:插入HashMap的键对象...

    java中Map集合的常用遍历方法及HashMap的应用实例

    1、遍历Map.entrySet():它的每一个元素都是Map.Entry对象,这个对象中, 放着的就是Map中的某一对key-value; 2、遍历Map.keySet():它是Map中key值的集合,我们可以通过遍历这个集合来 读取Map中的元素; 3、...

    map遍历的四种方式及性能比较

    这种方法相对于遍历`entrySet`来说性能更好(大约快10%),并且代码更简洁。但需要注意的是,这种方法只适用于只需要键或值的情况。 #### 方法三:使用Iterator遍历 在某些情况下,可能需要在遍历过程中修改`Map`...

    java Map 遍历方法

    2. **遍历HashMap** 使用`entrySet()`或`keySet()`的方式同样适用于遍历`HashMap`。 ```java HashMap, Object&gt; hash = new HashMap(); hash.put(3, 3); hash.put(4, 4); hash.put(5, 5); hash.put(6, 6); ...

Global site tag (gtag.js) - Google Analytics