Oracle Java ConcurrentHashMap 的错误实现?
Wrong implementation of Oracle Java ConcurrentHashMap?
我正在测试 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
。
我在这里错过了什么?
来自 javadoc 的实际代码:
if (map.get(key) == null) {
V newValue = mappingFunction.apply(key);
if (newValue != null)
map.put(key, newValue); // <-
}
}
如您所见,标记行中没有 return
关键字。
第 "return" 节还说:
Returns:
the current (existing or computed) value associated with the specified key, or null if the computed value is null
ConcurrentMap.computeIfAbsent
的代码示例没有反映实际意图,很可能是 putIfAbsent
的非直觉行为导致的错误,而实现遵循记录的意图。这已在 JDK-8174087 中报告
和 fixed in Java 9
请注意 Map.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)
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
提供的实现接口。
为了完整性,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;
}
我正在测试 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
。
我在这里错过了什么?
来自 javadoc 的实际代码:
if (map.get(key) == null) {
V newValue = mappingFunction.apply(key);
if (newValue != null)
map.put(key, newValue); // <-
}
}
如您所见,标记行中没有 return
关键字。
第 "return" 节还说:
Returns: the current (existing or computed) value associated with the specified key, or null if the computed value is null
ConcurrentMap.computeIfAbsent
的代码示例没有反映实际意图,很可能是 putIfAbsent
的非直觉行为导致的错误,而实现遵循记录的意图。这已在 JDK-8174087 中报告
和 fixed in Java 9
请注意 Map.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) 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
提供的实现接口。
为了完整性,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; }