ConcurrentHashMap putIfAbsent()返回null

时间:2014-02-07 07:29:46

标签: java concurrenthashmap

以下程序正在打印NULL。我无法理解为什么。

public class ConcurrentHashMapTest {
    public static final ConcurrentMap<String, String> map = new ConcurrentHashMap<>(5, 0.9f, 2);

    public static void main(String[] args) {
        map.putIfAbsent("key 1", "value 1");
        map.putIfAbsent("key 2", "value 2");

        String value = get("key 3");
        System.out.println("value for key 3 --> " + value);
    }

    private static String get(final String key) {
        return map.putIfAbsent(key, "value 3");
    }
}

有人可以帮我理解这种行为吗?

9 个答案:

答案 0 :(得分:21)

ConcurrentMap.putIfAbscent返回与指定键关联的先前值,如果没有键的映射,则返回null。您没有与“键3”关联的值。一切正确

答案 1 :(得分:14)

问题在于,根据定义, putIfAbsent 返回旧值而不是新值(缺席的旧值始终为null)。使用 computeIfAbsent - 这将为您返回新值。

private static String get(final String key) {
    return map.computeIfAbsent(key, s -> "value 3");
}

答案 2 :(得分:7)

putIfAbsent()返回与指定键关联的先前值,如果没有该键的映射,则返回null,并且因为key 3在地图中不存在,所以它返回{ {1}}。

您已在地图中添加了nullkey 1,但key 2未与任何值相关联。所以你得到key 3。使用某个值映射nullkey 3将返回与该键相关联的先前值。

如果地图已包含与值putIfAbsent()相关联的key 3

A

然后,在致电key 3 ---> A 时,将返回map.putIfAbsent("key 3","B")

答案 3 :(得分:5)

This is a frequently asked question, which perhaps suggest this behaviour is unintuitive. Maybe the confusion comes from the way dict.setdefault() works in python and other languages. Returning the same object you just put helps cut a few lines of code.

Consider:

if (map.contains(value)){
    obj = map.get(key);
}
else{
    obj = new Object();
}

versus:

obj = map.putIfAbsent(key, new Object());

答案 4 :(得分:4)

它在javadoc中:

  

返回与指定键关联的先前值,如果没有键的映射

,则返回null

答案 5 :(得分:3)

请阅读ConcurrentHashMap.putIfAbsent的文档:

  

<强>返回
      与指定键关联的先前值,如果没有键的映射,则为null

由于密钥"key 3"没有以前的值,它会返回null

答案 6 :(得分:2)

如果你查看文档,就会说

  

返回:
与指定键关联的先前值,或   如果没有键的映射

,则返回null

在您的情况下,之前没有与该关键字相关联的值,因此NULL

答案 7 :(得分:0)

可以使用 merge 函数返回当前映射的值。如果键已存在,则以下可能会返回当前的非空值,如果映射不存在或值为 null,则返回给定的新值。

private static String get(final String key) {
    return map.merge(key, "value 3", (oldVal, newVal) -> oldVal);
}

或者一般来说:

private T get(final String key, T value) {
    return map.merge(key, value, (oldVal, newVal) -> oldVal);
}

当您不喜欢使用 computeIfAbsent 时,这可能很有用,因为 computeIfAbsent 的映射函数可能会引发异常,并且您也不想执行以下操作:

map.putIfAbsent(key, value);
return map.get(key);

答案 8 :(得分:0)

所有答案都是正确的,只是补充一点,

<块引用>

如果指定的键尚未与值关联(或者是 映射到 null) 将它与给定的值相关联并返回 null, 否则返回当前值。

public V putIfAbsent(K key, V value) { 返回 putVal(key, value, true); }

密钥保存在表中。可以通过使用与 put 之前的原始键相等的键调用 get 方法来检索该值。如果在表中找不到该键,则返回 null。