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 super K, ? extends V> 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.computeIfAbsent
和Map.computeIfAbsent
关于返回值的记录意图,并且也等同于接口提供的default
实现。
为完整Map.computeIfAbsent
, Map.computeIfAbsent
的default
实现是
default V computeIfAbsent(K key, Function super K, ? extends V> 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