点赞在看,养成习惯。
点赞收藏,人生辉煌。
点击关注【微信搜索公众号:编程背锅侠】,防止迷路。
方法概述
如果指定的键尚未与值关联(或被映射到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);
}