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

2022-09-04 06:36:51

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

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

现在我想知道是否有充分的事实理由来做:

itemsByFoo.put(key, bars);

itemsByFoo.putIfAbsent(key, bars);

两者都有效:

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

SO:选择选项1或选项2的充分理由是“总是”吗?


答案 1

getOrDefault如果要在不修改映射的情况下对缺失值使用替身,则适用。如果要为缺少的键添加新值,可以在一个操作中直接执行此操作。

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

甚至

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

在最好的情况下,当被实现覆盖时,就像 一样,这将只进行单个哈希查找。MapHashMap

这不仅在使用实现时需要两次查找,而且,当然,大多数实现都会为其提供单个查找实现。尽管如此,在最好的情况下,和 的组合仍将具有两个查找,而优化的仅执行一个查找。putIfAbsentdefaultMapgetOrDefaultputIfAbsentcomputeIfAbsent


答案 2

重要的一点是,它需要一个,只有在缺少时才会执行,我们需要一个默认值。computeIfAbsentFunctionKeyValue

而需要默认值本身,已经计算过了。在这种情况下,我们需要的默认值是 ,它具有在堆上分配新对象的副作用。getOrDefaultValueValuenew ArrayList<Bar>()

我们希望推迟这样做,直到我们确定 尚未在 中。否则,我们将产生不必要的垃圾以供收集。keyitemsByFoogc