在使用getOrDefault()之后我应该使用put()还是putIfAbsent()?

Java8引入了那些不错的方法getOrDefault()putIfAbsent() ,允许编写如下代码:

 Map<Foo, List> itemsByFoo = ... List bars = itemsByFoo.getOrDefault(key, new ArrayList()); bars.add(someNewBar); 

现在我想知道是否有很好的事实理由:

 itemsByFoo.put(key, bars); 

要么

 itemsByFoo.putIfAbsent(key, bars); 

两者都有效:

  • 向列表添加元素时,选项1可能会执行大量不必要的“put”调用
  • 为新键添加新条目占主导地位时,option2可能会执行大量不必要的“containsKey”调用

SO:选择1或选项2“总是”的理由是什么?

如果您想在不修改地图的情况下使用替代值来获取缺席值,则getOrDefault是合适的。 如果要为缺席键添加新值,可以在一次操作中正确执行。

 List bars = itemsByFoo.computeIfAbsent(key, x -> new ArrayList<>()); bars.add(someNewBar); 

甚至

 itemsByFoo.computeIfAbsent(key, x -> new ArrayList<>()).add(someNewBar); 

在最好的情况下,当被Map实现覆盖时,就像使用HashMap ,这将只承担一次哈希查找。

并非putIfAbsent在使用default实现时只进行两次查找,但是,当然,大多数Map实现都会为它提供单个查找实现。 尽管如此, getOrDefaultputIfAbsent的组合在最佳情况下仍然会进行两次查找,而优化的computeIfAbsent只能进行一次查找。

关于computeIfAbsent一个重要的一点是它需要一个只在Key不存在时才能执行的Function ,我们需要一个默认Value

getOrDefault需要默认Value本身,已经计算好了。 在这种情况下,我们需要的默认Value是一个new ArrayList() ,它具有在堆上分配新对象的副作用。

我们希望推迟这样做,直到我们确定key不在itemsByFoo 。 否则我们会为gc生成不必要的垃圾来收集。