Java ConcurrentHashMap putIfAbsent()返回null

Java ConcurrentHashMap putIfAbsent()返回null,java,concurrenthashmap,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&q

以下程序正在打印
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");
    }
}
公共类ConcurrentHashMapTest{
公共静态最终ConcurrentMap=新ConcurrentHashMap(5,0.9f,2);
公共静态void main(字符串[]args){
putIfAbsent地图(“键1”、“值1”);
putIfAbsent地图(“键2”、“值2”);
字符串值=获取(“键3”);
System.out.println(“键3的值-->”+值);
}
私有静态字符串get(最终字符串密钥){
返回映射putIfAbsent(键,“值3”);
}
}

有人能帮我理解这个行为吗?

ConcurrentMap.putIfAbsent返回与指定键关联的上一个值,如果没有该键的映射,则返回null。您没有与“键3”关联的值。完全正确

注意:这不仅适用于
ConcurrentMap
,而且适用于
Map

的所有实现返回与指定键关联的先前值,或者如果键没有映射,则返回
null
,因为
键3
不在映射中,所以返回
null

您已经在地图中添加了
键1
键2
,但是
键3
与任何值都没有关联。所以你得到了一个
null
。使用某个值映射
键3
,并且
putIfAbsent()
将返回与该键关联的上一个值

例如,如果映射已经包含与值
A
关联的
键3

key 3 ---> A

然后调用
map.putIfAbsent(“键3”,“B”)
将返回
A
请阅读以下文档:

key 3 ---> A
返回
与指定键关联的上一个值,如果该键没有映射,则为
null

由于键
“键3”
没有以前的值,它返回
null

它在javadoc中:

返回与指定键关联的上一个值,如果该键没有映射,则返回null


如果你看一下文档,它会说

返回:
与指定键关联的上一个值,或 如果密钥没有映射,则为null


在您的情况下,以前没有与键关联的值,因此
NULL

这是一个常见问题,这可能表明此行为是不直观的。可能是由于dict.setdefault()在python和其他语言中的工作方式造成了混淆。返回刚才放置的同一对象有助于减少几行代码

考虑:

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

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

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

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

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

私有静态字符串获取(最终字符串键){
返回map.merge(键,“值3”,(oldVal,newVal)->oldVal);
}
或一般而言:

private T get(最终字符串键,T值){
返回map.merge(键,值,(oldVal,newVal)->oldVal);
}
当您不喜欢使用
computeIfAbsent
时,这可能很有用,因为到
computeIfAbsent
的映射函数可能会引发异常,并且您也不想执行以下操作:

map.putIfAbsent(键、值);
返回map.get(key);

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

如果指定的键尚未与值关联(或 映射到null)将其与给定值关联并返回null, else返回当前值

公共V值(K键,V值){ 返回putVal(key,value,true);}


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

您期望的行为是什么,为什么?对于引号,您应该使用
,而不是代码格式。是的,我忘了…:)已经有一段时间没有响应了,它不允许异常抛出,太糟糕了。和其他lambda一样。因此,要么使用@Skillythrows,要么使用rethrow exception作为RuntimeException。
@Skillythrows
是邪恶的。选中的异常比@Skillythrows:)更邪恶。这是一个原子操作吗?如中所示,映射能否在contains和get之间更改?