前言
V getOrDefault(Object key, V defaultValue)
void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
V putIfAbsent(K key, V value)
boolean remove(Object key, Object value)
replace
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
总结
前言 Map接口在1.8版本新增以下几个有趣的方法,今天参考源码来学习一下.
getOrDefault
replaceAll
putIfAbsent
remove
replace
computeIfAbsent
computeIfPresent
compute
merge
V getOrDefault(Object key, V defaultValue) 这可以说是最常用的方法了吧,获取指定key的value,当key不存在的时候返回一个默认值,也就是第二个参数.
1 2 3 4 5 6 7 default V getOrDefault (Object key, V defaultValue) { V v; return (((v = get(key)) != null ) || containsKey(key)) ? v : defaultValue; }
void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) 将所有value替换成给定lambda的计算结果,lambda的作用为根据key和value算出新的value.
源代码如下:
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 default void replaceAll (BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); for (Map.Entry<K, V> entry : entrySet()) { K k; V v; try { k = entry.getKey(); v = entry.getValue(); } catch (IllegalStateException ise) { throw new ConcurrentModificationException (ise); } v = function.apply(k, v); try { entry.setValue(v); } catch (IllegalStateException ise) { throw new ConcurrentModificationException (ise); } } }
示例代码如下:
1 2 3 4 5 6 7 8 9 10 @Test public void test1 () { Map<Integer, Integer> test = new HashMap <>(); test.put(1 , 1 ); test.put(2 , 2 ); System.out.println(test.toString()); test.replaceAll((k, v) -> k + v); System.out.println(test.toString()); }
这段代码中传递了一个lambda,作用是将key和value相加作为新的value.
输出结果如下:
V putIfAbsent(K key, V value) 当key不存在的时候,写入新值.始终返回执行操作后的新值.
源代码如下:
1 2 3 4 5 6 7 8 default V putIfAbsent (K key, V value) { V v = get(key); if (v == null ) { v = put(key, value); } return v; }
测试代码及输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void test2 () { Map<Integer, Integer> test = new HashMap <>(); test.put(1 , 1 ); test.put(2 , 2 ); System.out.println(test.toString()); test.putIfAbsent(1 , 3 ); test.putIfAbsent(3 , 3 ); System.out.println(test.toString()); } ------------------------ {1 =1 , 2 =2 } {1 =1 , 2 =2 , 3 =3 }
boolean remove(Object key, Object value) 如果给定的key在map中的value与给定值相等,则移除并且返回true,否则返回false.
1 2 3 4 5 6 7 8 9 default boolean remove (Object key, Object value) { Object curValue = get(key); if (!Objects.equals(curValue, value) || (curValue == null && !containsKey(key))) { return false ; } remove(key); return true ; }
replace 这个有两个重载方法.
default boolean replace(K key, V oldValue, V newValue) 当key在map中的value与给定的oldValue相等,则用newValue替换掉并且返回true,否则返回false.
1 2 3 4 5 6 7 8 9 10 11 default boolean replace (K key, V oldValue, V newValue) { Object curValue = get(key); if (!Objects.equals(curValue, oldValue) || (curValue == null && !containsKey(key))) { return false ; } put(key, newValue); return true ; }
V replace(K key, V value) 当key存在,就替换掉并且返回新值,否则返回null.
1 2 3 4 5 6 7 8 default V replace (K key, V value) { V curValue; if (((curValue = get(key)) != null ) || containsKey(key)) { curValue = put(key, value); } return curValue; }
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) 如果key不存在,则使用lambda计算并写入新值.永远返回执行操作后的新值.(可以存在,不做任何操作);放回计算的新值.
这个方法可以为一些耗时或者耗资源的操作构建本地缓存,当元素存在时直接返回,当不存在的时候进行耗时进行并存储,下一次可以直接返回.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 default V computeIfAbsent (K key, Function<? super K, ? extends V> mappingFunction) { Objects.requireNonNull(mappingFunction); V v; if ((v = get(key)) == null ) { V newValue; if ((newValue = mappingFunction.apply(key)) != null ) { put(key, newValue); return newValue; } } return v; }
测试代码及输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void test3 () { Map<Integer, Integer> test = new HashMap <>(); test.put(1 , 1 ); test.put(2 , 2 ); System.out.println(test.toString()); test.computeIfAbsent(1 , key -> key + 2 ); test.computeIfAbsent(3 , key -> key + 2 ); System.out.println(test.toString()); } ------------------------ {1 =1 , 2 =2 } {1 =1 , 2 =2 , 3 =5 }
V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 当key存在时,计算新值,如果新值不为空,则将新值写入,如果新值为空,则移除掉此key.返回新值或者null.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 default V computeIfPresent (K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); V oldValue; if ((oldValue = get(key)) != null ) { V newValue = remappingFunction.apply(key, oldValue); if (newValue != null ) { put(key, newValue); return newValue; } else { remove(key); return null ; } } else { return null ; } }
测试代码及输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void test4 () { Map<Integer, Integer> test = new HashMap <>(); test.put(1 , 1 ); test.put(2 , 2 ); System.out.println(test.toString()); test.computeIfPresent(1 , (key, oldValue) -> key + oldValue + 2 ); test.computeIfPresent(3 , (key, oldValue) -> key + oldValue + 2 ); System.out.println(test.toString()); } ------------------------------- {1 =1 , 2 =2 } {1 =4 , 2 =2 }
这个方法基本上是上一个方法的存在版本,但是要注意传入的lambda,参数是两个,computeIfAbsent的lambda传入key,计算值. 而computeIfPresent传入key和旧的value,并且由他们两个计算得到新的值.
V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 直接计算新值,新值为空,则删除key并且返回null,新值不为空则写入并且返回新值.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 default V compute (K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); V oldValue = get(key); V newValue = remappingFunction.apply(key, oldValue); if (newValue == null ) { if (oldValue != null || containsKey(key)) { remove(key); return null ; } else { return null ; } } else { put(key, newValue); return newValue; } }
测试代码及输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test5 () { Map<Integer, Integer> test = new HashMap <>(); test.put(1 , 1 ); test.put(2 , 2 ); System.out.println(test.toString()); test.compute(1 , (key, oldValue) -> key + 2 ); test.compute(3 , (key, oldValue) -> key + 2 ); test.compute(2 , (key, oldValue) -> null ); System.out.println(test.toString()); } ---------------- {1 =1 , 2 =2 } {1 =3 , 3 =5 }
测试代码中对2进行compute->null,结果是2被删除.
V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) 使用旧值和给定的value来计算新值,如果新值为空,则删除key,不为空则写入并且返回.
注意:如果旧值为空,也就是原有的key不存在,新值等于给定值,不会再进行计算.因此下方的测试代码3=10
而不是12.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 default V merge (K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); Objects.requireNonNull(value); V oldValue = get(key); V newValue = (oldValue == null ) ? value : remappingFunction.apply(oldValue, value); if (newValue == null ) { remove(key); } else { put(key, newValue); } return newValue; }
测试代码及输出如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void test6 () { Map<Integer, Integer> test = new HashMap <>(); test.put(1 , 1 ); test.put(2 , 2 ); System.out.println(test.toString()); test.merge(1 , 10 , (v, oldV) -> v + oldV + 2 ); test.merge(3 , 10 , (v, oldV) -> v + oldV + 2 ); test.merge(2 , 10 , (v, oldV) -> null ); System.out.println(test.toString()); } -------------------------- {1 =1 , 2 =2 } {1 =13 , 3 =10 }
总结 其实看过源码就可以发现,除了Function
,BiFunction
等函数式接口(也就是用于lambda)的接口是新声明的,其他调用的API都是原先已有的put
,get
,contain
等常用API,因此这些新的方法并不能算是很难用的新功能,只能算是一些免去开发人员重复工作的语法糖,我们当然要多多享受语法糖带来的便利,但是不能忘却原理,要多多熟悉再使用.
完。
ChangeLog
2019-05-13 完成
以上皆为个人所思所得,如有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文链接。
联系邮箱:huyanshi2580@gmail.com
更多学习笔记见个人博客——>呼延十