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

Gho*_*ica 12 java collections dictionary java-8

Java8介绍那些漂亮的方法getOrDefault()putIfAbsent(),让写代码,如:

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

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

itemsByFoo.put(key, bars);
Run Code Online (Sandbox Code Playgroud)

要么

itemsByFoo.putIfAbsent(key, bars);
Run Code Online (Sandbox Code Playgroud)

两者都有效:

  • 选项1时可能做了很多不必要的"放"的呼叫将元素添加到列表中经常发生
  • 为新键添加新条目占主导地位时,option2可能会执行大量不必要的"containsKey"调用

那么:选择1或选项2"总是"的充分理由是什么?

Hol*_*ger 20

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

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

甚至

itemsByFoo.computeIfAbsent(key, x -> new ArrayList<>()).add(someNewBar);
Run Code Online (Sandbox Code Playgroud)

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

putIfAbsent在使用default实现时,并不是只有两次查找,但是,当然,大多数Map实现都会为它提供单个查找实现.不过,组合getOrDefaultputIfAbsent仍然将承担在最好的情况下两个查找,而优化的computeIfAbsent确实只有一个.

  • @Eugene:这是一个通用的“地图”问题。原子性不是必需的。否则,您还有很多事情要做。虽然您可以使插入线程安全地在 `compute` 中执行所有操作,但它与最终读取 `List` 的代码无关,并且必须有代码读取它,如果存储本身不是目的,那么对于任何现实生活中的案例,无论如何都需要额外的努力。 (5认同)

Joh*_*lan 6

一个重要的一点computeIfAbsent是它需要一个Function只有在Key缺席时才能执行,我们需要一个默认值Value.

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

我们希望推迟这样做,直到我们确定它还key没有itemsByFoo.否则我们会产生不必要的垃圾gc来收集.