Java 为什么ConcurrentHashMap阻止空键和值?
的JavaDoc说: 与Java 为什么ConcurrentHashMap阻止空键和值?,java,concurrenthashmap,Java,Concurrenthashmap,的JavaDoc说: 与Hashtable类似,但与HashMap不同,此类不允许将null用作键或值 我的问题:为什么 第二个问题:Hashtable为什么不允许空值 我使用了很多HashMaps来存储数据。但是当切换到ConcurrentHashMap时,由于NullPointerException,我多次遇到麻烦。ConcurrentHashMap是线程安全的。我认为不允许空键和值是确保线程安全的一部分。不能在空键上同步 编辑:这并不是为什么在这种情况下。我最初认为锁定并发更新或使用对象监
Hashtable
类似,但与HashMap
不同,此类不允许将null
用作键或值
我的问题:为什么
第二个问题:Hashtable
为什么不允许空值
我使用了很多HashMaps来存储数据。但是当切换到
ConcurrentHashMap
时,由于NullPointerException,我多次遇到麻烦。ConcurrentHashMap是线程安全的。我认为不允许空键和值是确保线程安全的一部分。不能在空键上同步
编辑:这并不是为什么在这种情况下。我最初认为锁定并发更新或使用对象监视器检测是否修改了某些内容是一件很奇妙的事情,但经过检查,我似乎错了——它们使用基于哈希的位掩码的“段”进行锁定
在这种情况下,我怀疑他们这样做是为了复制Hashtable,我怀疑Hashtable这样做是因为在关系数据库世界中,null!=null,因此使用null作为键没有任何意义。我想下面的API文档片段给出了一个很好的提示: “此类在依赖其线程安全性但不依赖其同步详细信息的程序中可与哈希表完全互操作。”
他们可能只是想让
ConcurrentHashMap
与Hashtable
完全兼容/互换。由于Hashtable不允许空键和值,Josh Bloch设计了HashMap;Doug Lea设计了ConcurrentHashMap
。我希望那不是诽谤。事实上,我认为问题在于空值通常需要包装,以便真正的空值可以代表未初始化。如果客户机代码需要空值,那么它可以支付包装空值本身的成本(诚然很小)。我认为,至少在一定程度上,它允许您将containsKey
和get
组合到一个调用中。如果映射可以保存null,则无法判断get
是否返回null,因为没有该值的键,或者仅仅因为该值为null
为什么这是个问题?因为没有安全的方法自己去做。以下面的代码为例:
if (m.containsKey(k)) {
return m.get(k);
} else {
throw new KeyNotPresentException();
}
由于m
是一个并发映射,可以在containsKey
和get
调用之间删除键k,导致此代码段返回一个从未在表中出现过的null,而不是所需的KeyNotPresentException
通常情况下,您可以通过同步来解决这个问题,但是如果使用并发映射,那么这当然不起作用。因此,get
的签名必须更改,以向后兼容的方式执行此操作的唯一方法是防止用户首先插入空值,并继续将其用作“找不到密钥”的占位符
ConcurrentMaps中不允许使用null的主要原因
(ConcurrentHashMaps,ConcurrentSkipListMaps)是不是歧义
在非并发映射中可能勉强可以容忍,但不可能
适应。主要的一点是,如果map.get(key)
返回null
,则
无法检测密钥是否显式映射到null
vs密钥未映射
映射。在非并发映射中,您可以通过
map.contains(key)
,但在并发映射中,映射可能已更改
通话间隙
我不认为不允许空值是正确的选择。 在许多情况下,我们确实希望将一个具有null值的键放入con-current映射中。但是,通过使用ConcurrentHashMap,我们无法做到这一点。
我建议即将发布的JDK版本可以支持这一点。?没有对映射的键和值执行同步。那没有意义。还有其他类型的锁定。这就是它“并发”的原因。为了做到这一点,它需要一个挂起的对象。为什么内部没有一个可以用来同步空值的speciall对象?e、 g.“私有对象NULL=新对象();”。我想我以前见过这个…你指的是什么其他类型的锁定?事实上,现在我看了源代码,我对此有严重的怀疑。它似乎使用了段锁定,而不是对单个项进行锁定。为什么哈希表不支持null?从它的代码来看,我看不出哈希表不允许null值的明显原因。也许这只是API在创建类时做出的决定?!HashMap在内部对空情况有一些特殊的处理,而Hashtable没有。(它总是抛出NullPointerException。)我认为这是一个非常恼人的不一致性。EnumMap也不允许null。显然,不允许空密钥的技术限制是不存在的。对于映射,简单的V型字段将提供对空键的支持(如果您想区分空值和无值,可能是另一个布尔字段)。更好的问题是“为什么HashMap允许空键和空值?”。或者可能是“为什么Java允许null驻留在所有类型中?”,或者甚至是“为什么Java有null?”。谢谢,但是让null作为键怎么样?为什么不使用
Optional
s作为值呢internally@benez可选
是Java 8的一项功能,在当时(Java 5)是不可用的。您现在确实可以使用可选的s了。@AmitW,我认为ans是一样的,即歧义。例如,假设一个线程将一个键设为null,并针对它存储一个值。然后另一个线程将另一个密钥更改为null。当第二个线程尝试添加新值时,它将被替换。如果第二个线程尝试获取值,它将获取另一个键的值,该键由第一个线程修改。应该避免这种情况。您可以执行map.getOrDefault(key,NULL\u标记)
。如果是null
,则该值为null
。如果返回NULL\u MAR