转自:http://swiftlet.net/archives/1259

HashMap的遍历有两种方式,如下所示:
第一种利用entrySet的方式:

 
1
2
3
4
5
6
7
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
   Object key = entry.getKey();
   Object val = entry.getValue();
}

上面的方式可以变化为for循环的形式:

 
1
2
3
4
5
Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
    entry.getKey();
    entry.getValue();
}

第二种利用keySet的方式:

 
1
2
3
4
5
6
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
    Object key = iter.next();
    Object val = map.get(key);
}

上面的方式也可以变化为for循环的形式:

 
1
2
3
4
Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
    map.get(key);
}

这两种方式那种效率高呢?可以从下面的试验可以看出来:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test
{
    public static void main(String[] args)
    {
        HashMap<String, String> map = new HashMap<String, String>();
        for (int i = 0; i < 1000000; i++)
        {
            map.put(i + "", "hello world");
        }
        long begin1 = System.currentTimeMillis();
        Iterator iterator1 = map.entrySet().iterator();
        while (iterator1.hasNext())
        {
            Map.Entry entry = (Map.Entry) iterator1.next();
            Object key1 = entry.getKey();
            Object val1 = entry.getValue();
        }
        long end1 = System.currentTimeMillis();
        System.out.println("map.entrySet方式变量花费的时间为:" + (end1 - begin1));
        long begin2 = System.currentTimeMillis();
        Iterator iterator2 = map.keySet().iterator();
        while (iterator2.hasNext())
        {
            Object key2 = iterator2.next();
            Object val2 = map.get(key2);
        }
        long end2 = System.currentTimeMillis();
        System.out.println("map.keySet方式变量花费的时间为:" + (end2 - begin2));
    }
}

结论:
经过运行多次,我发现两者的运行时间相差不多,而且没有明确显示出那种变量方式更快一些。有的人可能会觉得第一种变量方式会快一些,因为他们觉得:keySet方式其实是遍历了2次,一次是转为iterator,一次就从HashMap中取出key所对应的value,而entry方式只遍历了一次,把key和value都放到了entry中,所以entry方式更快一些。
但是我觉得这种分析的方式比较主观,我们更应该从源码的角度去分析。首先看一下迭代器的源码:
keySet的迭代器:

 
1
2
3
4
5
private final class KeyIterator extends HashIterator<K> {
    public K next() {
        return nextEntry().getKey();
    }
}

entrySet的迭代器:

 
1
2
3
4
5
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
    public Map.Entry<K,V> next() {
        return nextEntry();
    }
}

从上面我们可以看到只是返回值不同而已,父类相同,所以性能相差不多。下面我们再看一下get方法的源码:

 
1
2
3
4
5
6
public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
 
1
2
3
4
5
6
7
8
9
10
11
12
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}

从上面的源码发现get的时间复杂度取决于for循环循环次数,即hash算法。所以两种性能差别不大。从上面的分析来看,我们得到最终的结论:
(1)HashMap的循环,如果既需要key也需要value,直接用

 
1
2
3
4
5
Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
    entry.getKey();
    entry.getValue();
}

即可,foreach简洁易懂。
(2)如果只是遍历key而无需value的话,可以直接用

 
1
2
3
4
Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
    // key process
}

HashMap两种遍历方式的深入研究的更多相关文章

  1. Java HashMap两种遍历方式

    第一种: Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Ma ...

  2. HashMap的两种遍历方式

    HashMap的两种遍历方式 HashMap存储的是键值对:key-value . java将HashMap的键值对作为一个整体对象(java.util.Map.Entry)进行处理,这优化了Hash ...

  3. Map的两种遍历方式

    ********************************************************************************* ****************** ...

  4. Map集合的两种遍历方式

    Map集合:即 接口Map<K,V> map集合的两种取出方式:    1.Set<k> keyset: 将map中所有的键存入到set集合(即将所有的key值存入到set中) ...

  5. HashMap两种遍历数据的方式

    HashMap的遍历有两种方式,一种是entrySet的方式,另外一种是keySet的方式. 第一种利用entrySet的方式: Map map = new HashMap(); Iterator i ...

  6. Java HashMap 四种遍历方式

    HashMap遍历方式包含以下4种: 1.遍历KeySet,再通过Key来getValue. 2.使用entrySet的迭代器. 3.foreach entrySet的方式. 3.foreache v ...

  7. python中的字典两种遍历方式

    dic = {"k1":"v1", "k2":"v2"} for k in dic: print(dic[K]) for ...

  8. 关于使用lazytag的线段树两种查询方式的比较研究

    说到线段树,想来大家并不陌生——最基本的思路就是将其规划成块,然后只要每次修改时维护一下即可. 但是尤其是涉及到区间修改时,lazytag的使用往往能够对于程序的质量起到决定性作用(Ex:一般JSOI ...

  9. hashmap两种遍历方法

    第一种:使用entryset来进行遍历 Map map=new HashMap(); Iterator iter=map.entrySet().iterator(); while(iter.hasNe ...

随机推荐

  1. 分享公司DAO层动态SQL的一些封装

    主题 公司在DAO层使用的框架是Spring Data JPA,这个框架很好用,基本不需要自己写SQL或者HQL就能完成大部分事情,但是偶尔有一些复杂的查询还是需要自己手写原生的Native SQL或 ...

  2. hibernate学习三(使用Annotation,注解)

    一.新建一个工程hibernate_02_HelloWorld_Annotation(复制01工程并重命名); 二.新建一个实体类teacher.java,数据库中新建teacher表; import ...

  3. HTML Select 标签选择后触发jQuery事件代码实例

    页面设计原由: 因为很多客户不知道如何来到我们公司,领导想让我在微信公众号上面做一个链接,客户可以直接通过微信公众号打开地图并导航到我们公司的办公地点. 实现起来并不难,但由于公司有很多办事处,所以需 ...

  4. 函数式 js 接口实现原理,以及 lodash/fp 模块

    函数式 js 接口 之前在 youtube 上看到一个技术视频,讲“underscore.js的接口为什么不好用”,以及什么样的接口更好用.演讲者是 lodash.js 的作者,他提出了一种“全面函数 ...

  5. gitlab使用个人版v16.11

    title: gitlab使用个人版v16.11 date: 2016-11-13 20:53:00 tags: [gitlab] --- 1.安装gitbash 附上地址链接:git 2.配置git ...

  6. vs写python扩展资料收集

    总结: 1.创建dll工程: 2.增加包含头文件路径 :将python路径下的include加入到包含头文件路径:在工程属性页 C/C++/附加包含目新增<Python>\include目 ...

  7. jQuery中的选择器

    (1)基本#id element .class * selector1,selector2,selectorN (2)层次选择器:ancestor descendant parent > chi ...

  8. 3篇NeuroImage文献分析

    鉴于之前读的一些文章很容易就忘掉了,故打算花点时间记录下所读的文献. 这几天花了一些时间读了3篇文献: Intersubject consistency of cortical MEG signals ...

  9. 一对一还是一对多? MVP设计前提

    设计MVP之前,先要确定好以下模块之间是一对多还是一对一的关系: View ---> Presenter --> Model --> Interface(URL) 就是一个View只 ...

  10. linux 软连接和硬链接

    硬链接 ln sourceFile targetFile 硬链接只能给文件创建,不能为目录建立硬链接,硬链接不能跨分区创建,  硬链接会增加inode连接数, 硬链接的文件删除不影响其他文件 课外: ...