Java 8 Map中putIfAbsent和computeIfAbsent有什么区别?

Ade*_*lin 53 java java-8

阅读一篇有趣的文章,这些人声称这两个功能的区别在于:

如果Map中没有指定的Key,则两个函数都希望添加元素.

putIfAbsent添加具有指定Value的元素,而computeIfAbsent添加具有使用Key计算的值的元素. http://www.buggybread.com/2014/10/java-8-difference-between-map.html

我们已经看到putIfAbsent删除了必须定义if语句的必要方法,但是如果获取Java文章真的会损害我们的性能呢?

为了优化这一点,我们不想在我们确定需要它们之前获取文章 - 这意味着在获取文章之前我们需要知道密钥是否缺失. http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/

我还没准备好了解哪些差异可以请你详细说明这两个功能?

And*_*eas 96

差异#1

computeIfAbsent 采用映射函数,如果缺少键,则调用该函数以获取值.

putIfAbsent 直接取值.

如果获取的值很昂贵,那么putIfAbsent如果密钥已经存在则会浪费.

一个常见的"昂贵"值是例如new ArrayList<>()当你创建一个时Map<K, List<V>>,当密钥已经存在时创建一个新列表(然后丢弃新列表)会产生不必要的垃圾.


差异#2

computeIfAbsent 返回"与指定键关联的当前(现有或已计算)值,如果计算值为null,则返回null".

putIfAbsent 返回"与指定键关联的先前值,如果没有键的映射,则返回null".

因此,如果密钥已经存在,它们将返回相同的内容,但如果密钥丢失,则computeIfAbsent返回计算值,同时putIfAbsent返回null.


差异#3

两种方法都将"缺席"定义为关键缺失或现有值为null,但是:

computeIfAbsent 如果密钥不存在,则不会设置空值.

putIfAbsent 如果密钥不存在,将放置该值,即使该值为null.

这使得对未来没有什么区别调用computeIfAbsent,putIfAbsent以及get调用,但它确实像呼叫差异getOrDefaultcontainsKey.

  • 您刚刚保存了我的一天!谢谢。 (3认同)
  • 不同的返回语义很令人困惑,这就是我最终在这里阅读您非常有帮助的答案的方式。 (3认同)
  • 您好,我想我的意思是这两种方法都不会返回传递给它们的新值。谢谢您的回答。 (2认同)

Era*_*ran 46

假设你有一个Map<String,ValueClass>.

map.putIfAbsent("key", new ValueClass());
Run Code Online (Sandbox Code Playgroud)

ValueClass无论如何都会创建一个实例,即使"key"键已经在Map.这只会创建一个不必要的实例.

另一方面

map.computeIfAbsent("key", k -> new ValueClass());
Run Code Online (Sandbox Code Playgroud)

ValueClass如果"key"键不在Map(或映射到某个null值),则只会创建一个实例.

因此computeIfAbsent效率更高.

putIfAbsent 相当于:

ValueClass value = new ValueClass();
if (map.get("key") == null) {
    map.put("key",value);
}
Run Code Online (Sandbox Code Playgroud)

虽然computeIfAbsent相当于:

if (map.get("key") == null) {
    map.put("key",new ValueClass());
}
Run Code Online (Sandbox Code Playgroud)

两种方法之间的另一个小差异是computeIfAbsent不会null为缺席密钥设置值.putIfAbsent将.

  • computeIfAbsent的一个相当常见的用途是`Map <X,List <Y >>`,你必须在第一次遇到键值时创建一个List.最初一个人做了一个get,test,new,put ......现在它只是`computeIfAbsent(...,new ArrayList())` (7认同)

Jes*_*per 9

您可以通过仔细查看方法签名来理解差异:

  • putIfAbsent 接受一个键和值,如果映射中没有该键的值,则将该值放入映射中。
  • computeIfAbsent需要一把钥匙和一个Function. 如果映射中没有该键的值,则调用该函数来创建该值,然后将该值放入映射中。

如果您已经拥有该值,请使用putIfAbsent.

如果您还没有该值并且创建该值是一项代价高昂的操作(例如,必须在数据库中查找该值),则使用computeIfAbsent,这样就不需要执行代价高昂的操作,以防万一映射已包含指定键的值。


zla*_*kad 7

也许默认实现可以澄清一点....

default V putIfAbsent?(K key, V value) 对于此映射,默认实现等效于:

 V v = map.get(key);
  if (v == null)
      v = map.put(key, value);
  return v;
Run Code Online (Sandbox Code Playgroud)

另一方面:

default V computeIfAbsent?(K key,
                          Function<? super K,? extends V> mappingFunction)
Run Code Online (Sandbox Code Playgroud)

相当于:

if (map.get(key) == null) {
     V newValue = mappingFunction.apply(key);
     if (newValue != null)
         map.put(key, newValue);
}
Run Code Online (Sandbox Code Playgroud)