computeIfAbsent是java8的新方法,它定义在Map接口中,和我们常用的putIfAbsent有着类似的功能,都是在map不存在某个key的时候(其实还有一种情况,key存在,但是对应的value为null,从下面的源码也可以看出),进行插入
computeIfAbsent代码
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) { //这里if为true的情况包括了key不存在和key对应的value为null,下同
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) { //新的value为null,则不会执行操作,即不会插入key
put(key, newValue);
return newValue;
}
}
return v;
}
putIfAbsent代码
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
查看它们的源码,可以比较清晰的了解两者的区别。
- computeIfAbsent第二个参数接收的是一个函数式接口Function(在实际调用中通常使用lambda表达式或方法引用),函数输入是key,计算得到value。如果这个key不存在,则将计算得到的value进行插入,返回新的value。否则,返回原先的值。可以认为,返回的值就是执行此操作后的value值,无论是否进行了插入
- putIfAbsent第二个参数直接接收value。如果对应的key不存在,将value插入,返回null。否则,不插入,返回原值。这里返回的值是原先的value值,如果key不存在,原先对应的value为null,自然就会返回null.
- 以上内容在其他的文章中也有说明,不过除此之外我觉得还有一点需要强调的是,如果对应的key已经存在了,那么computeIfAbsent不会执行value表达式的方法,而putIfAbsent会执行。
一个简单的测试代码如下
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.putIfAbsent("a", buildValue("a"));
map.computeIfAbsent("b", key -> buildValue(key));
System.out.println("========");
map.putIfAbsent("a", buildValue("a"));
map.computeIfAbsent("b", key -> buildValue(key));
}
private static String buildValue(String s) {
System.out.println("build value: " + s);
return s;
}
}
输出
build value: a
build value: b
========
build value: a
可以看到,第二次调用putIfAbsent,尽管我们知道没有执行插入,但是仍然执行了buildValue方法,但是第二次调用computeIfAbsent,却没有触发buildValue方法。
其实根据源码也可以看出,putIfAbsent的value是作为方法参数进行传入的,所以不管是否插入都会执行计算得到value。而computeIfAbsent的value是在Function中的方法返回值,只有需要插入时才会执行(就是源码中mappingFunction.apply(key)这里)