compute和putAbsent源码分析及案例

643 阅读4分钟

compute源码分析及案例

描述

校验这个计算函数是否为空,为空抛出空指针异常。使用给定的key和获取到的oldValue计算出一个新的值newValue。在新值为空的前提下,如果旧的值不为空,或者这个集合中包含这个key,则删除这个key,并且返回null。在新值为空的前提下,如果旧的值为空,并且集合不包含这个key,什么都不做,直接返回null。如果新值不为空,添加这个新值和指定的key到集合,这里可能是新增操作【新值不为空,集合中不存在这个key】或者是替换操作【新值不为空,集合中这个key,对应的val为null】,返回这个新值。

参数

  • key:与指定值关联的键
  • remappingFunction:计算值的函数

返回值

在新值为空的前提下,如果旧的值不为空,或者这个集合中包含这个key,则删除这个key,并且返回null。在新值为空的前提下,如果旧的值为空,并且集合不包含这个key,什么都不做,直接返回null。如果新值不为空,添加这个新值和指定的key到集合,这里可能是新增操作【新值不为空,集合中不存在这个key】或者是替换操作【新值不为空,集合中这个key,对应的val为null】,返回这个新值。

源码分析

default V compute(K key,
      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
 // 校验这个计算函数是否为空,为空抛出空指针异常
  Objects.requireNonNull(remappingFunction);
  // 使用给定的key获取值,赋值给oldValue
 V oldValue = get(key);
  // 使用给定的key和获取到的oldValue计算出一个新的值newValue
 V newValue = remappingFunction.apply(key, oldValue);
  // 判断这个新的值是否为空
 if (newValue == null) {
  // 如果在新值为空的前提下,旧的值不为空,或者这个集合中包含这个key
  if (oldValue != null || containsKey(key)) {
   // 删除这个key,并且返回null
   remove(key);
   return null;
  } else {
   // 如果在新值为空的前提下,旧的值为空,并且集合不包含这个key,什么都不做,直接返回null
   return null;
  }
 } else {
  // 新值不为空,添加这个新值和指定的key到集合
    // 这里可能是新增操作【新值不为空,集合中不存在这个key】或者是替换操作【新值不为空,集合中这个key,对应的val为null】
  put(key, newValue);
    // 返回这个新值
  return newValue;
 }
}

案例

@Test
public void test_compute_01(){
 Map<String, String> map = new HashMap<>();
 String key = "aaa";
 String msg = "hahh";
 // key对应的val不存在,会将key和msg添加到集合中,并返回这个msg,这个执行的是新增操作
 String compute = map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg));
 System.out.println(compute);
 map.forEach((k, v) -> System.out.println("=======key: " + k + "========v: " + v));
}

@Test
public void test_compute_01_val_null(){
 Map<String, String> map = new HashMap<>();
 String key = "aaa";
 String msg = null;
 // key对应的val不存在,会将key和msg添加到集合中,并返回这个msg
 String compute = map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg));
 System.out.println(compute);
 map.forEach((k, v) -> System.out.println("=======key: " + k + "========v: " + v));
}

@Test
public void test_compute_02(){
 Map<String, String> map = new HashMap<>();
 String key = "aaa";
 String msg = "hahh";
 map.put(key, "uuu");
 // key对应的val存在,并且不为空,使用concat函数在原有的val后面追加新值,并返回追加后的新值,然后添加到集合中
 String compute = map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg));
 System.out.println(compute);
 map.forEach((k, v) -> System.out.println("=======key: " + k + "========v: " + v));
}

@Test
public void test_compute_03(){
 //java8 实现计算功能统计字符串出现次数
 Map<String, Integer> map = new HashMap<>();
 List<String> source = Arrays.asList("hello", "world", "hello", "welcome", "hello", "hello", "welcome", "world");
 source.forEach(s -> map.compute(s, (k, v) -> Objects.isNull(v) ? 1 : v + 1));
 System.out.println(map);
}

putIfAbsent源码分析及案例

描述

根据key获取旧的val,如果旧的值不为空,返回旧的val,如果旧的val为空【这个集合要支持val为空】,返回新添加的val,这个新添加的val可能为null。

参数

  • Key:与指定值关联的键
  • value:与指定键关联的值

返回值

如果旧的值不为空,返回旧的val,如果旧的val为空【这个集合要支持val为空】,返回新添加的val,这个新添加的val可能为null。

源码分析

default V putIfAbsent(K key, V value) {
  // 根据key获取旧的val
 V v = get(key);
 // 判断旧的val是否为空
 if (v == null) {
   // 旧的val为空,将这个key和value添加到集合中
  v = put(key, value);
 }
 // 如果旧的值不为空,返回旧的val,如果旧的val为空,返回新添加的val,这个新添加的val可能为null
 return v;
}

案例

@Test
public void test_putAbsent_01(){
 // HashMap是允许键和值为null的
 Map<String, String> map = new HashMap<>();
 // 验证key和val键值对在集合中都不存在
 map.putIfAbsent("aaa", "hhh");
 map.forEach((k, v) -> System.out.println("===key: " + k + "===value: " + v));
}

@Test
public void test_putAbsent_02(){
 Map<String, String> map = new HashMap<>();
 // HashMap是允许键和值为null的
 map.put("aaa", null);
 // 验证key和val都存在集合中,但是key对应的val为null
 map.putIfAbsent("aaa", "bbb");
 map.forEach((k, v) -> System.out.println("===key: " + k + "===value: " + v));
}

@Test
public void test_putAbsent_03(){
 Map<String, String> map = new HashMap<>();
 map.put("aaa", "bbb");
 // 验证key和val都存在集合中,并且key对应的val不为null
 map.putIfAbsent("aaa", "ccc");
 map.forEach((k, v) -> System.out.println("===key: " + k + "===value: " + v));
}