在使用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
实现都会为它提供单个查找实现。 尽管如此, getOrDefault
和putIfAbsent
的组合在最佳情况下仍然会进行两次查找,而优化的computeIfAbsent
只能进行一次查找。
关于computeIfAbsent
一个重要的一点是它需要一个只在Key
不存在时才能执行的Function
,我们需要一个默认Value
。
而getOrDefault
需要默认Value
本身,已经计算好了。 在这种情况下,我们需要的默认Value
是一个new ArrayList
,它具有在堆上分配新对象的副作用。
我们希望推迟这样做,直到我们确定key
不在itemsByFoo
。 否则我们会为gc
生成不必要的垃圾来收集。