我正在测试 ConcurrentHashMap
关于 Oracle 的 Java 8 实现:
ConcurrentMap<String, String> 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
Javadoc of computeIfAbsent
是这么说的
Implementation Requirements:
The default implementation is equivalent to the following steps for this map, then returning the current value or null if now absent:
if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) return map.putIfAbsent(key, newValue); }
它说然后返回当前值,如果现在不存在则返回 null。那么它不应该返回 null
吗?假设 putIfAbsent
也返回 null
。
我在这里错过了什么?
最佳答案
ConcurrentMap.computeIfAbsent
的代码示例没有反射(reflect)实际意图,很可能是 putIfAbsent
的非直觉行为导致的错误,而实现遵循记录的意图。这已在 JDK-8174087 中报告
和 fixed in Java 9
请注意 Map.computeIfAbsent
的契约(Contract)是
Implementation Requirements:
The default implementation is equivalent to the following steps for this map, then returning the current value or null if now absent:
if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) map.put(key, newValue); }
省略 return
语句。但是明明说
Returns:
the current (existing or computed) value associated with the specified key, or null if the computed value is null
是ConcurrentMap.computeIfAbsent
的文档试图合并并发方面,落入 putIfAbsent
的非直观行为:
Implementation Requirements:
The default implementation is equivalent to the following steps for this map, then returning the current value or null if now absent:
if (map.get(key) == null) { V newValue = mappingFunction.apply(key); if (newValue != null) return map.putIfAbsent(key, newValue); }
但它还是说
Returns:
the current (existing or computed) value associated with the specified key, or null if the computed value is null
并且记录的意图应该优先于代码示例。请注意,实际的 default
implementation of ConcurrentMap.computeIfAbsent
符合记录的意图:
@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; }
所以 the implementation of ConcurrentHashMap.computeIfAbsent
确实符合关于返回值的 ConcurrentMap.computeIfAbsent
和 Map.computeIfAbsent
的文档意图,并且也等效于提供的 default
实现通过接口(interface)。
为了完整起见,Map.computeIfAbsent
的默认
实现是
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; }
关于java - Oracle Java ConcurrentHashMap 的错误实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46272108/