Map集合中的computeIfAbsent的用法以及源码分析

Map集合中的computeIfAbsent的用法以及源码分析

方法概述

如果指定的键尚未与值关联(或被映射到null),则尝试使用给定的映射函数计算其值,并将其输入到这个映射中,除非null。

如果函数返回null,则不记录映射。如果函数本身抛出了一个(未选中的)异常,则重抛异常,并且不记录映射。 最常见的用法是构造一个新的对象作为初始映射值或备忘结果。

请求参数

  • key 指定的值将与之相关联。
  • mappingFunction 计算数值的函数。

返回值

与指定键相关联的当前值(现有值或计算值),如果计算值为空,则为空。

异常

  • 如果指定的键为空,而这个映射不支持空键,或者映射函数为空,则抛出NullPointerException。
  • 如果该集合不支持put操作,则出现UnsupportedOperationException异常。
  • 如果指定的键或值的类阻止它被存储在这个映射中,则ClassCastException异常。

源码分享

default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction)
{
// 判断这个映射函数是否为空,为空抛出NullPointerException
Objects.requireNonNull(mappingFunction);
V v;
// 判断指定的额key对应的val是否为空
if ((v = get(key)) == null) {
V newValue;
// 判断映射函数计算出来的newValue是否为空
if ((newValue = mappingFunction.apply(key)) != null) {
// 不为空将这个key和计算出来的val存到集合
put(key, newValue);
// 并返回这个计算出来的val
return newValue;
}
}
// 判断指定的额key对应的val不为空直接返回val
return v;
}
复制代码

测试代码

测试包含指定key

 @Test
public void test_computeIfAbsent_contains(){
Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
Set<String> s = new HashSet<>();
String canonicalName = "m";
s.add("mm");
dependentBeanMap.put(canonicalName, s);
Set<String> dependentBeans =
dependentBeanMap.computeIfAbsent(canonicalName, k -> {
LinkedHashSet<String> set = new LinkedHashSet<>(8);
set.add("hheh");
return set;
});
// 判断集合中是否包含这个元素
System.out.println(dependentBeanMap.containsKey(canonicalName));
System.out.println();
// 获取这个元素对应的val值,并遍历
dependentBeanMap.get(canonicalName).forEach(System.out::println);
System.out.println();
// 返回值的遍历,返回值其实就是key对应的val的值
dependentBeans.forEach(System.out::println);
}
复制代码

测试不包含指定key

 /**
* 测试不包含指定key
*/

@Test
public void test_computeIfAbsent(){
Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
String canonicalName = "hahha";
// 原来的集合中是否存在这个key对应的val,不存在就创建一个set集合,并在set中添加一个元素
// todo 如果把Function函数替换为k -> new LinkedHashSet<>(8);那么就是返回了一个我们创建的空的set集合,然后我们再在外层做一些设置set集合的参数,下面的todo [这一步8]操作
Set<String> dependentBeans =
dependentBeanMap.computeIfAbsent(canonicalName, k -> {
LinkedHashSet<String> set = new LinkedHashSet<>(8);
set.add("hheh");
return set;
});
// 判断集合中是否包含这个元素
System.out.println(dependentBeanMap.containsKey(canonicalName));
System.out.println();
// 获取这个元素对应的val值,并遍历
dependentBeanMap.get(canonicalName).forEach(System.out::println);
System.out.println();
// 返回值的遍历,看看是否加入了我们设置的valhheh,返回值其实就是key对应的val的值
dependentBeans.forEach(System.out::println);
System.out.println();
// set集合添加一个测试。todo [这一步8]
dependentBeans.add("hello");
dependentBeans.forEach(System.out::println);
}
复制代码

测试空指针异常

 /**
* 测试空指针异常 ConcurrentHashMap不允许k和v为空
*/

@Test
public void test_computeIfAbsent_npe() {
Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
String canonicalName = null;
// 原来的集合中是否存在这个key对应的val,不存在就创建一个set集合,并在set中添加一个元素
// todo 如果把Function函数替换为k -> new LinkedHashSet<>(8);那么就是返回了一个我们创建的空的set集合,然后我们再在外层做一些设置set集合的参数,下面的todo [这一步8]操作
Set<String> dependentBeans =
dependentBeanMap.computeIfAbsent(canonicalName, k -> new HashSet<>());
}
复制代码

一个统计出现次数的算法

 @Test
public void test_computeIfAbsent_times(){
//实现计算功能统计字符串出现次数
Map<String, AtomicInteger> countMap = new HashMap<>();
List<String> source = Arrays.asList("hello", "world", "hello", "welcome", "hello", "hello", "welcome", "world");
source.forEach(s -> countMap.computeIfAbsent(s, key -> new AtomicInteger()).getAndIncrement());
System.out.println(countMap);
}
复制代码
求公众号关注
求公众号关注

猜你喜欢

转载自juejin.im/post/5ef05bf6e51d457423262296