Hashmap七种实现方式在性能安全上的对比
七种实现方式及分类
因为创建的方式一样 所以所有的创建hashmap只做一次
// 创建并赋值 HashMap
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "JDK");
map.put(3, "Spring Framework");
map.put(4, "MyBatis framework");
map.put(5, "Java中文社群");
1 迭代器Entryset
// 遍历
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
System.out.print(entry.getKey());
System.out.print(entry.getValue());
}
2迭代器keyset
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
}
3ForEach EntrySet
// 遍历
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
}
4ForEach KeySet
// 遍历
for (Integer key : map.keySet()) {
System.out.print(key);
System.out.print(map.get(key));
}
5Lambda
// 遍历
map.forEach((key, value) -> {
System.out.print(key);
System.out.print(value);
});
Streams API 单线程
// 遍历
map.entrySet().stream().forEach((entry) -> {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
});
Streams API 多线程
// 遍历
map.entrySet().parallelStream().forEach((entry) -> {
System.out.print(entry.getKey());
System.out.print(entry.getValue());
});
类型 | 结果 | |
---|---|---|
1 | 迭代器 EntrySet | 1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群 |
2 | 迭代器 KeySet | 1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群 |
3 | ForEach EntrySet | 1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群 |
4 | .ForEach KeySet | 1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群 |
5 | Lambda | 1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群 |
6 | Streams API 单线程 | 1 Java 2 JDK 3 Spring Framework 4 MyBatis framework 5 Java中文社群 |
7 | Streams API 多线程 | 4 MyBatis framework 5 Java中文社群 1 Java 2 JDK 3 Spring Framework |
性能测试:
经过oracle官方提供的性能测试jmh测试得出的实验结果为:
其中 Score 列表示平均执行时间, ±
符号表示误差。从以上结果可以看出,如果加上后面的误差值的话,可以得出的结论是,除了并行循环的 parallelStream
性能比极高之外(多线程方式性能肯定比较高),其他方式的遍历方法在性能方面几乎没有任何差别。
解析原因
解析所有 遍历代码(通过javac编译成字节码)
package com.example;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class HashMapTest {
static Map<Integer, String> map = new HashMap() {
{
for(int var1 = 0; var1 < 2; ++var1) {
this.put(var1, "val:" + var1);
}
}
};
public HashMapTest() {
}
public static void main(String[] var0) {
entrySet();
keySet();
forEachEntrySet();
forEachKeySet();
lambda();
streamApi();
parallelStreamApi();
}
public static void entrySet() {
Iterator var0 = map.entrySet().iterator();
while(var0.hasNext()) {
Entry var1 = (Entry)var0.next();
System.out.println(var1.getKey());
System.out.println((String)var1.getValue());
}
}
public static void keySet() {
Iterator var0 = map.keySet().iterator();
while(var0.hasNext()) {
Integer var1 = (Integer)var0.next();
System.out.println(var1);
System.out.println((String)map.get(var1));
}
}
public static void forEachEntrySet() {
Iterator var0 = map.entrySet().iterator();
while(var0.hasNext()) {
Entry var1 = (Entry)var0.next();
System.out.println(var1.getKey());
System.out.println((String)var1.getValue());
}
}
public static void forEachKeySet() {
Iterator var0 = map.keySet().iterator();
while(var0.hasNext()) {
Integer var1 = (Integer)var0.next();
System.out.println(var1);
System.out.println((String)map.get(var1));
}
}
public static void lambda() {
map.forEach((var0, var1) -> {
System.out.println(var0);
System.out.println(var1);
});
}
public static void streamApi() {
map.entrySet().stream().forEach((var0) -> {
System.out.println(var0.getKey());
System.out.println((String)var0.getValue());
});
}
public static void parallelStreamApi() {
map.entrySet().parallelStream().forEach((var0) -> {
System.out.println(var0.getKey());
System.out.println((String)var0.getValue());
});
}
}
从结果可以看出,除了lambda和streams api,其他的遍历方式最终生成的方式都是在循环中遍历一个entry,因此其实性能都差不多,但是更推荐entryset(更优雅)
安全测试:
1,迭代器方式
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
if (entry.getKey() == 1) {
// 删除
System.out.println("del:" + entry.getKey());
iterator.remove();
} else {
System.out.println("show:" + entry.getKey());
}
}
结果:安全
show:0
del:1
show:2
2.for循环方式
for (Map.Entry<Integer, String> entry : map.entrySet()) {
if (entry.getKey() == 1) {
// 删除
System.out.println("del:" + entry.getKey());
map.remove(entry.getKey());
} else {
System.out.println("show:" + entry.getKey());
}
}
结果:不安全
3.Lambda 方式
map.forEach((key, value) -> {
if (key == 1) {
System.out.println("del:" + key);
map.remove(key);
} else {
System.out.println("show:" + key);
}
}); //错误方法
// 根据 map 中的 key 去判断删除
map.keySet().removeIf(key -> key == 1);
map.forEach((key, value) -> {
System.out.println("show:" + key);
});//正确方法
结果:可以先使用 Lambda
的 removeIf
删除多余的数据,再进行循环是一种正确操作集合的方式。
4.Stream 方式
方式1:
map.entrySet().stream().forEach((entry) -> {
if (entry.getKey() == 1) {
System.out.println("del:" + entry.getKey());
map.remove(entry.getKey());
} else {
System.out.println("show:" + entry.getKey());
}
});
结果:不安全
方式2:
map.entrySet().stream().filter(m -> 1 != m.getKey()).forEach((entry) -> {
if (entry.getKey() == 1) {
System.out.println("del:" + entry.getKey());
} else {
System.out.println("show:" + entry.getKey());
}
});
结果:安全
show:0
show:2
可以使用 Stream
中的 filter
过滤掉无用的数据,再进行遍历也是一种安全的操作集合的方式。
总结:
性能方面
:除了Stream的并行循环其他的都差不多
简洁性选择
Lambda 和 Stream
安全性:
System.out.println("del:" + entry.getKey());
} else {
System.out.println("show:" + entry.getKey());
}
});
``
######结果:安全
show:0
show:2
可以使用 Stream
中的 filter
过滤掉无用的数据,再进行遍历也是一种安全的操作集合的方式。
总结:
性能方面
:除了Stream的并行循环其他的都差不多
简洁性选择
Lambda 和 Stream
安全性:
使用迭代器提供的 iterator.remove()
方法来进行删除,这种方式是安全的在遍历中删除集合的方式,或者使用 Stream 中的 filter
过滤掉要删除的数据再进行循环,也是安全的操作方式。