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);
	}

求公众号关注

猜你喜欢

转载自blog.csdn.net/wildwolf_001/article/details/106902752