作者:晨风流云 | 来源:互联网 | 2023-06-22 21:20
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 super K> 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 super Map.Entry> 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 super K, ? super V> 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();
}
效率更高
for (String key : map.keySet()) {
//操作key
}