Oracle Java ConcurrentHashMap的错误实现?

use*_*188 12 java oracle concurrenthashmap java-8

我正在测试ConcurrentHashMapOracle的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
Run Code Online (Sandbox Code Playgroud)

中的JavadoccomputeIfAbsent不说

实施要求:

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

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

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

我在这里错过了什么?

Hol*_*ger 16

代码示例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);
}
Run Code Online (Sandbox Code Playgroud)

省略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);
}
Run Code Online (Sandbox Code Playgroud)

但它仍然说

返回:

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

并且记录的意图应该优先于代码示例.请注意,实际default执行情况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;
}
Run Code Online (Sandbox Code Playgroud)

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

为了完整性,default执行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;
}
Run Code Online (Sandbox Code Playgroud)

  • TL; DR,这只是文档中的一个不好的例子? (3认同)