Oracle Java ConcurrentHashMap的错误实现?

我在Oracle的Java 8实现上测试ConcurrentHashMap

 ConcurrentMap concurrentMap = new ConcurrentHashMap(); String result = concurrentMap.computeIfAbsent("A", k -> "B"); System.out.println(result); // "B" result = concurrentMap.putIfAbsent("AA", "BB"); System.out.println(result); // null 

computeIfAbsent的Javadoc确实这么说

实施要求:

默认实现等效于此映射的以下步骤,然后返回当前值,如果现在不存在则返回null:

 if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) return map.putIfAbsent(key, newValue); } 

它表示然后返回当前值,如果现在不存在则返回null 。 那么它不应该返回null吗? 鉴于putIfAbsent也返回null

我在这里想念的是什么?

ConcurrentMap.computeIfAbsent的代码示例不反映实际意图,很可能是由putIfAbsent的非直观行为引起的错误,而实现遵循记录的意图。 这已在JDK-8174087中报告并在Java 9中修复

请注意, Map.computeIfAbsent的合同是

实施要求:

默认实现等效于此映射的以下步骤,然后返回当前值,如果现在不存在则返回null:

 if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) map.put(key, newValue); } 

省略return语句。 但清楚地说

返回:

与指定键关联的当前(现有或已计算)值,如果计算值为null,则返回null

它是ConcurrentMap.computeIfAbsent的文档,它试图结合并发方面,因为putIfAbsent的非直观行为:

实施要求:

默认实现等效于此映射的以下步骤,然后返回当前值,如果现在不存在则返回null:

 if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) return map.putIfAbsent(key, newValue); } 

但它仍然说

返回:

与指定键关联的当前(现有或已计算)值,如果计算值为null,则返回null

并且记录的意图应该优先于代码示例。 请注意, ConcurrentMap.computeIfAbsent的实际default实现符合记录的意图:

 @Override default V computeIfAbsent(K key, Function mappingFunction) { Objects.requireNonNull(mappingFunction); V v, newValue; return ((v = get(key)) == null && (newValue = mappingFunction.apply(key)) != null && (v = putIfAbsent(key, newValue)) == null) ? newValue : v; } 

因此, ConcurrentHashMap.computeIfAbsent的实现确实符合ConcurrentMap.computeIfAbsentMap.computeIfAbsent关于返回值的记录意图,并且也等同于接口提供的default实现。

为完整Map.computeIfAbsentMap.computeIfAbsentdefault实现是

 default V computeIfAbsent(K key, Function mappingFunction) { Objects.requireNonNull(mappingFunction); V v; if ((v = get(key)) == null) { V newValue; if ((newValue = mappingFunction.apply(key)) != null) { put(key, newValue); return newValue; } } return v; } 

来自javadoc的实际代码:

  if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) map.put(key, newValue); // <- } } 

如您所见,标记行中没有return关键字。

“返回”部分还说:

返回:与指定键关联的当前( 现有或计算 )值,如果计算值为null,则返回null