`

为KeySet遍历HashMap辟谣---效率问题

阅读更多
    听某位高级软件开发工程师说遍历HashMap的三种方式,用KeySet遍历的方式会非常慢,效率特别低,所以推荐使用EntrySet的方式遍历HashMap,这两种都是可以获取到HashMap的key-value对,另外一种遍历HashMap的方式是调用HashMap的values方法,但是无法得到key的值。当听到说keyset特别慢,效率低下的时候,我就在想,如果这样真的那么慢的话,那么jdk是不是早就把这样的方式给废弃了啊,或者加上@Deprecated了。所以我想着证明一下。看以下代码
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class JudgeHashMap {
	public static void main(String[] args) {
		Map<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
		for (int i = 0; i < 1000000; i++) {
			hashMap.put(i, i);
		}
		long start = System.nanoTime();
		Set<Integer> set = hashMap.keySet();
		Iterator<Integer> iterator = set.iterator();
		while (iterator.hasNext()) {
			iterator.next();
		}
		long mid = System.nanoTime();
		System.out.println("keySet用的时间是" + (mid - start) / 1e10 + "秒");
		long mid2 = System.nanoTime();
		Set<Entry<Integer, Integer>> sEntries = hashMap.entrySet();
		Iterator<Entry<Integer, Integer>> iterator2 = sEntries.iterator();
		while (iterator2.hasNext()) {
			iterator2.next();
		}
		long end = System.nanoTime();
		System.out.println("entrySet用的时间是" + (end - mid2) / 1e10 + "秒");
		long end2 = System.nanoTime();
		Collection<Integer> collection = hashMap.values();
		Iterator<Integer> iterator3 = collection.iterator();
		while (iterator3.hasNext()) {
			iterator3.next();
		}
		long end3 = System.nanoTime();
		System.out.println("values用的时间是" + (end3 - end2) / 1e10 + "秒");
	}
}

   得到的结果是
keySet用的时间是0.0022835033秒
entrySet用的时间是0.0024659158秒
values用的时间是0.0022196947秒
   keyset遍历容量为100万的hashmap用时就比entryset多用了0.0004秒。当hashmap的容量比较小的情况下,两者的差距其实可以忽略不计了。
那到底是因为什么引发了这个时间上的差距呢,原因是keyset是通过entryset得到的,然后通过迭代keyset得到键值对,达到遍历的效果,所以会慢一点,但是绝对不是效率低下。所以当HashMap容量比较小的情况下,完全可以使用keyset的方式。
2
6
分享到:
评论
7 楼 sunway00 2013-08-07  

Map<Integer, String> hashMap = new HashMap<Integer, String>();
		List<String> values1 = new ArrayList<String>(1000000);
		List<String> values2 = new ArrayList<String>(1000000);
		
		
		for (int i = 0; i < 1000000; i++) {  
            hashMap.put(i, "aaaaaaaa");  
        }
		
		long start = System.nanoTime(); 
		
		for (Entry<Integer, String> entry : hashMap.entrySet()) {
			values1.add(entry.getValue());
		}
		
		long end = System.nanoTime();
		
		System.out.println("entrySet用的时间是" + (end - start) / 1e10 + "秒"); 
		
		Set<Integer> keySet = hashMap.keySet();
		long start2 = System.nanoTime();
		for (Integer integer : keySet) {
			values2.add(hashMap.get(integer));
		}
		long end2 = System.nanoTime();
		
		System.out.println("keySet用的时间是" + (end2 - start2) / 1e10 + "秒"); 


运行结果:
entrySet用的时间是0.0034094524秒
keySet用的时间是0.004261786秒

使用entrySet的主要原因是避免在再次执行 map.get(key),而根据测试,时间能相差1ms。
6 楼 Shen.Yiyang 2013-08-07  
ddlgyq 写道
lyplyz 写道
如果你在循环中只用key,则用keySet没问题
但如果你既要用key也要用value,则使用entrySet的效率确实比keySet
因为此时,如果你用keySet,你要多一次value = map.get(key),这个才是最大的消耗,你试试在while循环中把value取出来就知道了

取出value的时间对比,对于百万容量的hashMap的话 时间没差多少吧
keySet用的时间是0.0050171926秒
entrySet用的时间是0.0032048473秒
values用的时间是0.0021337984秒

4楼的意思是说,既然你要测试“获取到HashMap的key-value对”,那么用keyset的时候,就必须在循环里面一次次调用map.get(key),这样就慢了。你现在的测试是只得到了keyset,只是比entryset多做了一次 set的循环,没有获取key-value对。
5 楼 ddlgyq 2013-08-06  
lyplyz 写道
如果你在循环中只用key,则用keySet没问题
但如果你既要用key也要用value,则使用entrySet的效率确实比keySet
因为此时,如果你用keySet,你要多一次value = map.get(key),这个才是最大的消耗,你试试在while循环中把value取出来就知道了

取出value的时间对比,对于百万容量的hashMap的话 时间没差多少吧
keySet用的时间是0.0050171926秒
entrySet用的时间是0.0032048473秒
values用的时间是0.0021337984秒
4 楼 lyplyz 2013-08-06  
如果你在循环中只用key,则用keySet没问题
但如果你既要用key也要用value,则使用entrySet的效率确实比keySet
因为此时,如果你用keySet,你要多一次value = map.get(key),这个才是最大的消耗,你试试在while循环中把value取出来就知道了
3 楼 ddlgyq 2013-08-06  
alvin198761 写道
for(Entry<K,V> entry : hashMap.entrySet()){
//这样就行了,不用那么些,
}

2 楼 alvin198761 2013-08-06  
for(Entry<K,V> entry : hashMap.entrySet()){
//这样就行了,不用那么些,
}
1 楼 bitray 2013-08-06  
你写的很对,虽然老生常谈,但是说明一些高级工程师不求甚解,仅仅是照本宣科

相关推荐

    HashMap 概述 精讲 .md

    看完这篇 HashMap,和面试官扯皮就没问题了 - HashMap 概述 - HashMap 和 HashTable 的区别 - 相同点 - 不同点 - HashMap 和 HashSet 的区别 - HashMap 底层结构 - AbstractMap 类 - Map 接口 - 重要内部类...

    Python库 | django-keyset-pagination-plus-0.9.9.tar.gz

    python库。 资源全名:django-keyset-pagination-plus-0.9.9.tar.gz

    怎样遍历一个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-遍历map

    java,利用keySet进行遍历map

    DoubleAccessMap:可以通过使用值访问KeySet的HashMap

    DoubleAccessMap 可以通过使用值访问KeySet的HashMap

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

    2、遍历Map.keySet():它是Map中key值的集合,我们可以通过遍历这个集合来 读取Map中的元素; 3、遍历Map.values():它是Map中value的集合,我们可以直接通过这个集合遍历 Map中的值,却不能读取key。

    java遍历特例

    //hashmap keySet() 遍历 for(Object m: hash.keySet()){ System.out.println(m+"---"+hash.get(m)); } // treemap keySet()遍历 for(Object m: treeMap.keySet()){ System.out.println(m+...

    遍历MAP的几种方法

    遍历MAP的几种方法,利用keyset进行遍历,它的优点在于可以根据你所想要的key值得到你想要的 values,更具灵活性

    java HashMap的keyset实例

    简单地说,在keyset方法返回的set上做修改会改变原来hashmap,这也许不是你想要的,于是形成一个隐藏的bug

    Java Map遍历方式的选择

     对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多。理由是:entrySet方法一次拿到所有key和value的集合;而keySet拿到的只是key的集合,针对每个key,都要去Map中额外查找一次...

    java-hashmap:Java HashMap的插图

    Java HashMap的插图 Java HashMap HashMap类使用哈希表来实现Map接口。 这样,即使对于大型集合,诸如get()和put()之类的基本操作的执行时间也可以保持恒定。 目录 插图1:使用put()方法在HashMap中创建和...

    objection-keyset-pagination:Objection.js 的键集分页(基于光标的分页)插件

    Objection-keyset-pagination 是 ORM 的一个插件,用于实现基于键集的分页,也称为游标分页。 键集分页需要严格的记录排序。 在用户界面方面,键集分页与无限滚动元素配合得很好。 键集分页可提供稳定的结果。 下一...

    keyczar-cli:KeyczarTool 的简化 CLI

    keyczar-cli 周围的简单 bash 包装器。 KeyczarTool 管理您的 keyczar 加密密钥。... mkdir -p /path/to/project/keyset cd /path/to/project/keyset keyczar create --purpose=(sign|crypt) keyczar add

    Java源码解析HashMap的keySet()方法

    今天小编就为大家分享一篇关于Java源码解析HashMap的keySet()方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    sesvc.exe 阿萨德

    但是 HashMap 原有的问题也都存在,比如在并发场景下使用时容易出现死循环。 final HashMap, String&gt; map = new HashMap, String&gt;(); for (int i = 0; i ; i++) { new Thread(new Runnable() { @Override public...

    HDCP KSV和keyset对应关系介绍

    HDCP KSV和keyset对应关系介绍HDCP KSV和keyset对应关系介绍HDCP KSV和keyset对应关系介绍HDCP KSV和keyset对应关系介绍HDCP KSV和keyset对应关系介绍HDCP KSV和keyset对应关系介绍HDCP KSV和keyset对应关系介绍HDCP...

    官网下载:Windows-KB841290-x86-ENU.zip

    Fciv 1.21: Fixed bad keyset error on some computers. Fciv 1.22: Added -type option. Support up to 10 masks. *.exe *.dll ... Fciv 2.0: xml as unique storage. Added -both option. Fciv 2.01: Exit with ...

    谈谈Java中遍历Map的几种方法

    java中的map遍历有多种方法,从早的Iterator,到java5支持的foreach,再到java8 Lambda,让我们一起来看下具体的用法以及各自的优缺点。  先初始化一个map public class TestMap {  public static Map&lt;Integer&gt;...

    yada:Yada是又一个双数组trie库,旨在快速搜索和紧凑的数据表示

    亚达:又一个双阵列 Yada是又一个双数组特里库,旨在快速搜索...// make a keyset which have key-value pairs let keyset = & [ ( "a" . as_bytes (), 0 ), ( "ab" . as_bytes (), 1 ), ( "abc" . as_bytes (), 2

    django-infinite-scroll-pagination:基于查找方法键集分页的无偏移分页

    请注意,尽管有这个库的名称,它仍可以用作常规的分页器,更好的名称应该是seek-paginator , keyset-paginator , cursor-paginator或offset-less-paginator但现在为时已晚,哈哈:D这个怎么运作键集驱动的分页...

Global site tag (gtag.js) - Google Analytics