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

时间:2017-08-02 11:01:25

标签: java dictionary collections java-8

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“总是”的理由是什么?

2 个答案:

答案 0 :(得分:20)

如果您想在不修改地图的情况下使用替代值来替换缺席值,那么

getOrDefault是合适的。如果要为缺席键添加新值,可以在一次操作中正确执行。

List<Bar> 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只能进行一次。

答案 1 :(得分:5)

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

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

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