热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HashMap遍历方式性能比较

JDK8之前,可以使用ketSet或者entrySet来遍历HashMap,JDK8中引入了map.forEach来进行遍历1.keySet和entrySet1.1基本用法keyS

JDK8之前,可以使用ketSet或者entrySet来遍历HashMap,JDK8中引入了map.forEach来进行遍历

1. keySet和entrySet

1.1 基本用法

keySet:

Map map = new HashMap<>();
Iterator it = map.keySet().iterator();
Object key;
Object value;
while(it.hasNext()){
key = it.next();
value = map.get(key);//性能差异
System.out.println(key+":"+value);
}

entrySet:

Map map = new HashMap<>();
Iterator it = map.entrySet().iterator();
Object key;
Object value;
while(it.hasNext()){
Map.Entry entry = (Map.Entry)it.next();
key = entry.getKey();
value = entry.getValue();//性能差异
System.out.println(key+":"+value);
}

1.2 源码分析

keySet:

public Set keySet() {
Set ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
final class KeySet extends AbstractSet {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer action) {
Node[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i for (Node e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}

entrySet

public Set> entrySet() {
Set> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
final class EntrySet extends AbstractSet> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator> iterator() {
return new EntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry) o;
Object key = e.getKey();
Node candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry e = (Map.Entry) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator> spliterator() {
return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer> action) {
Node[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i for (Node e = tab[i]; e != null; e = e.next)
action.accept(e);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}

从源码中可以看出,当要得到某个value时,keySet需要从hashMap中get,entrySet相比keySet少了遍历table的过程,这就是两者性能上的主要差别

map.forEach()

default void forEach(BiConsumer action) {
Objects.requireNonNull(action);
for (Map.Entry entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}

源码分析可知,map.foreach()本质上还是使用的entrySet

实例

package com.feiyu.map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @author maokeluo
* @desc 遍历hashMap性能比较
* @create 17-9-2
*/
public class TraverseHsahMap {
public static void main(String[] args) throws InterruptedException {
Map map = new HashMap();
int num = 10000000;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i String temp = String.valueOf(i);
map.put(temp,temp);
}
}
});
thread.start();
thread.join();

//forEach map.entrySet
long start1 = System.currentTimeMillis();
for (Map.Entry entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}
long end1 = System.currentTimeMillis() - start1;
System.out.println("forEach map.entrySet遍历HashMap使用时间:"+end1);
//显式调用map.entrySet()的集合迭代器
long start2 = System.currentTimeMillis();
Iterator> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
entry.getKey();
entry.getValue();
}
long end2 = System.currentTimeMillis() - start2;
System.out.println("显式调用map.entrySet()的集合迭代器遍历HashMap使用时间:"+end2);
//forEach map.keySet在调用get取值
long start3 = System.currentTimeMillis();
for (String key : map.keySet()) {
map.get(key);
}
long end3 = System.currentTimeMillis() - start3;
System.out.println("forEach map.keySet在调用get取值遍历HashMap使用时间:"+end3);
//forEach map.entrySet(),用临时变量保存map.entrySet()
long start4 = System.currentTimeMillis();
Set> entrySet = map.entrySet();
for (Map.Entry entry : entrySet) {
entry.getKey();
entry.getValue();
}
long end4 = System.currentTimeMillis() - start4;
System.out.println("forEach map.entrySet(),用临时变量保存map.entrySet()使用时间:"+end4);
}
}

结果

| map size | 10000 | 100000 | 1000000 | 10000000 |
|&#8212;&#8212;&#8211;|&#8212;&#8212;&#8211;|
| forEach entrySet | 2ms | 11ms | 32ms | 199ms |
| for iterator entrySet| 1ms | 5ms | 29ms | 203ms |
| forEach keySet | 2ms | 7ms | 54ms | 273ms |
| for entrySet=entrySet()| 1ms | 5ms | 28ms | 189ms |

遍历方式结论总结

  • hashMap的循环遍历,如果不仅需要key又需要value,使用

for (Map.Entry entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}

效率更高

  • 如果只是遍历key不需要value,可以直接使用

for (String key : map.keySet()) {
//操作key
}

推荐阅读
  • 01Map集合概述A:Map集合概述:我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同a:Collection中的集合 ... [详细]
  • 图解HashMap
    什么是HashMap,文章内HashMap源码主要来自Android7.0HashMap是开发中常用的一个类,那么他究竟是什么呢?HashMap是一个存储key-value的集合, ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了源码分析--ConcurrentHashMap与HashTable(JDK1.8)相关的知识,希望对你有一定的参考价值。  Concu ... [详细]
  • Java集合详解5:深入理解LinkedHashMap和LRU缓存
    Java集合详解5:深入理解LinkedHashMap和LRU缓存今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存。具体代码在我的 ... [详细]
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • 转载自:http:www.blogjava.netCarpenterLeearchive20160427430268.html总体介绍之所以把HashSet和HashMa ... [详细]
  • 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的。LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉。先说说List:每 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 从相邻元素对还原数组的解题思路和代码
    本文介绍了从相邻元素对还原数组的解题思路和代码。思路是使用HashMap存放邻接关系,并找出起始点,然后依次取。代码使用了HashMap来存放起始点所在的adjacentPairs中的位置,并对重复的起始点进行处理。 ... [详细]
  • 一、HashSet1.虑重功能特性(HashMap实现)2.put(key)如果重复返回false***Add ... [详细]
  • 本篇文章给大家分享的是有关Java中怎么对HashMap按键值排序,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话 ... [详细]
  • 将学生对象和学生的归属地通过键与值存储到map集合中。importjava.util.HashMap;importjava.util.Iterator;importjava.uti ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
author-avatar
晨风流云
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有