前言:
Map是java中常用使用的一个集合类,它以键值对的形式存储数据。我们经常使HashMap、Concurrenthashmap等都是Map接口的实现类。在JDK8中Map集合类进行非常多的优化,比如。HashMap的数据结构从“数组+链表”变成了“数组+链表+红黑树”(PS:我会写一篇HashMap源码的文章);Concurrenthashmap在JDK7版本中使用“分段锁技术”保证线程安全,而JDK8中使用“synchronized+CAS”保证线程安全。此外,在JDK8中Map又新增了11个方法,增加了Map集合类使用的便捷性和灵活。这篇文章,我们将选取几个重要的方法进行使用,希望对大家的工作学习有些帮助。
正文:
一、新增的11个方法:
getOrDefault(Object key, V defaultValue)、forEach(BiConsumer<? super K, ? super V> action)、replaceAll(BiFunction<? super K, ? super V, ? extends V> function) 、putIfAbsent(K key, V value) 、remove(Object key, Object value) 、replace(K key, V oldValue, V newValue)、replace(K key, V value)、computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)、computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)、compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)、merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
二、重点方法的使用:
我在将用Map接口的实现类HashMap演示重点方法的使用,为了方便阅读和断点运行HashMap源码,我又将源码复制MyHashMap类中,以下事例都是实例化MyHashMap类,它的本质还是HashMap。
1.putIfAbsent(K key, V value):
作用:如果Map不存在这样的映射时,使用putIfAbsent(K key,V value)方法来添加键值对。
特点:key不存在时,添加key-value映射对; key为null时,覆盖value值
举例:
Map<String, String> map = new MyHashMap<>();
map.put("a1", "123");
map.put("a2", null);
map.putIfAbsent("a1", "a1");
map.putIfAbsent("a2", "a2");
map.putIfAbsent("a3", "a3");
map.putIfAbsent("a4", null);
System.out.println("遍历 map:"+map); //遍历 map:{a1=123, a2=a2, a3=a3, a4=null}
2.compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):
作用:获取指定key,通过BiFunction函数更新过的value值。
特点:如果在compute中传递的重映射函数返回null,则将映射从Map中删除;如果重映射函数引发异常,则异常为re-thrown,并且当前映射保持不变;在计算过程中,重新映射功能应该不能修改此映射。
举例:
Map<String, Integer> map = new MyHashMap<>();
map.put("aj1", 1000);
map.put("aj2", null);
map.put("aj3", 2000);
// compute简单使用:
Integer aj1 = map.compute("aj1", (key, value) -> value * 90 / 100);
System.out.println("aj1打9折: " + aj1); //aj1打9折: 900
// 证明1:如果在compute中传递的重映射函数返回null,则将映射从Map中删除(存在的key的value可以为空)。
Integer aj2 = map.compute("aj2", (key, value) -> value == null ? null : value * 90 / 100);
System.out.println("aj2打9折: " + aj2); //aj2打9折: null
// 证明2:如果重映射函数引发异常,则异常为re-thrown,并且当前映射保持不变
Integer aj3 = null;
try {
aj3 = map.compute("aj3", (key, value) -> "aj3".equals(key) ? value / 0 : value * 90 / 100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("aj3的值: " + map.get("aj3")); //aj3的值: 2000
System.out.println("打印map:" + map); //打印map:{aj1=900, aj3=2000}
3.computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction):
作用:获取不存在的key或映射值为null的key,通过Function函数更新过的value值。即key不存在时,计算value后,添加key-value映射对;key为null时,计算value后,覆盖value值。
特点:如果此方法的映射函数返回null,则不会为该键记录任何映射;在计算时,如果重新映射函数引发异常,则重新引发该异常,并且不记录任何映射;在计算过程中,不允许使用此方法修改此Map。
举例:
Map<String, Integer> map = new MyHashMap<>();
map.put("aj1", 1000);
map.put("aj2", null);
map.put("aj3", 1200);
Integer aj1 = map.computeIfAbsent("aj1", key -> 1500+100);
System.out.println("aj1存在时,返回原value:" + aj1); // aj1存在时,返回原value:1000
Integer aj2 = map.computeIfAbsent("aj2", key -> 1700);
System.out.println("aj2为空时,覆盖value值:" + aj2); // aj2为空时,覆盖value值:1700
Integer aj4 = map.computeIfAbsent("aj4", key -> 2000);
System.out.println("aj4不存在时,添加value值:" + aj4); // aj4不存在时,添加value值:2000
System.out.println("打印map:" + map); //打印map:{aj2=1700, aj1=1000, aj4=2000, aj3=1200}
// 统计出现数量
Map<String, AtomicInteger> map1 = new MyHashMap<>();
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("2");
list.add("4");
list.add("5");
list.add("1");
list.forEach(str -> map1.computeIfAbsent(str, key -> new AtomicInteger()).incrementAndGet());
System.out.println("打印map1:" + map1);
4.computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):
作用:获取存在的key或映射值为null的key,通过BiFunction函数更新过的value值
特点:如果此方法的映射函数返回null,则将删除该映射(前提,存在的key的value不为空);如果重新映射函数引发异常,则重新引发该异常,并且映射保持不变;在计算过程中,不允许使用此方法修改此Map
举例:
Map<String, Integer> map = new MyHashMap<>();
map.put("aj1", 1000);
map.put("aj2", null);
map.put("aj3", 2000);
Integer aj1 = map.computeIfPresent("aj1", (key, value) -> value == null ? null : value * 90 / 100);
System.out.println("aj1打9折: " + aj1); // aj1打9折: 900
Integer aj2 = map.computeIfPresent("aj2", (key, value) -> value == null ? null : value * 90 / 100);
System.out.println("aj2打9折: " + aj2); // aj2打9折: null
Integer aj4 = map.computeIfPresent("aj4", (key, value) -> value == null ? null : value * 90 / 100);
System.out.println("aj4打9折: " + aj4); // aj4打9折: null
// 证明:如果此方法的映射函数返回null,则将删除该映射(前提,存在的key的value不为空);
Integer aj3 = map.computeIfPresent("aj3", (key, value) -> value != null ? null : value * 90 / 100);
System.out.println("aj3打9折: " + aj3); // aj3打9折: null
System.out.println("打印map:" + map); // 打印map:{aj2=null, aj1=900}
5.merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction):
作用:获取key,通过BiFunction函数计算组合一个键的多个映射值。
特点:如果键不存在或与null关联,则仅将键以及Hashmap中的相应值作为新条目输出;如果键已经具有某个值,则“重新映射功能”会将旧值和新值都与给定键合并。
举例:
// 仓库1鞋种类及个数
Map<String, Integer> map1 = new MyHashMap<>();
map1.put("aj1", 10);
map1.put("aj2", 3);
map1.put("aj3", 5);
// 仓库2鞋种类及个数
Map<String, Integer> map2 = new MyHashMap<>();
map2.put("aj2", 8);
map2.put("aj3", 1);
map2.put("aj4",10);
// 使用merge计算合计
map2.forEach((key, value) ->
map1.merge(key, value, (v1, v2) ->
v1.equals(v2) ? v1 : v1 + v2)
);
System.out.println("所有仓库的鞋的种类及个数:" + map1); // 所有仓库的鞋的种类及个数:{aj2=11, aj1=10, aj4=10, aj3=6}