为什么ConcurrentHashMap不允许插入null值?

简介: 在Java语言中,给ConcurrentHashMap和Hashtable这些线程安全的集合中的Key或者Value插入 null(空) 值的会报空指针异常,但是单线程操作的HashMap又允许 Key 或者 Value 插入 null(空) 值。这到底是为什么呢?

需要面试文档的扫描下方二维码

在Java语言中,给ConcurrentHashMap和Hashtable这些线程安全的集合中的Key或者Value插入  null(空)  值的会报空指针异常,但是单线程操作的HashMap又允许  Key   或者  Value   插入  null(空) 值。这到底是为什么呢?

1、探寻源码

为了找到原因,我们先来看这样一段源码片段,打开ConcurrentHashMap的putVal()方法,源码中第一句就非常明确地做了判断,如果  Key   或者  Value  为 null(空) 值,就直接抛出空指针异常。

2e4fefeb99b9dcabd2430c0a51cf016d.png

我们在源码中似乎已经找到了原因,你可以这样回答面试官,说JDK源码就是这么规定的。然而,这个原因是不能说服面试官的,虽然,源码是这样设计的,我们要思考的是,这样设计背后更深层次的原因。

那到底为什么ConcurrentHashMap不允许插入 null (空)值,HashMap又允许插入呢?

2、歧义问题

因为给ConcurrentHashMap中插入 null (空)值会存在歧义。我们可以假设ConcurrentHashMap允许插入 null(空) 值,那么,我们取值的时候会出现两种结果:

89b5bb1142bbfe8b5f1f3a60f0e4a0d8.png

1、值没有在集合中,所以返回的结果就是 null (空);

2、值就是 null(空),所以返回的结果就是它原本的 null(空) 值。

这就产生了歧义问题。

那HashMap允许插入 null(空) 值,难道它就不担心出现歧义吗?这是因为HashMap的设计是给单线程使用的,所以如果取到 null(空) 值,我们可以通过HashMap的  containsKey(key)方  法来区分这个 null(空) 值到底是插入值是 null(空),还是本就没有才返回的 null(空) 值。

而 ConcurrentHashMap 就不一样了,因为 ConcurrentHashMap 是在多线程场景下使用的,它的情况更加复杂。

举个例子,现在有线程T1调用了  ConcurrentHashMap  的  containsKey(key)  方法,我们期望返回的结果是false,也就是说,T1并没有往ConcurrentHashMap中   put   null(空)值。

181c25295eb72d8b7e1576e1db2ad89c.png

但是,恰恰出了个意外,在线程T1还没有得到返回结果之前,线程T2又调用了ConcurrentHashMap 的 put() 方法,插入了一个Key,并且存入的Value是 null(空) 值。那么,线程T1 最终得到的返回结果就变成 true 了。

618391b399bf4ff9a9257c9834ed062d.png

显然,这个结果和我们之前期望的 false 完全不一致。

也就是说,在多线程的复杂情况下,我们多线程的复杂情况下,到底是插入的 null(空)  值,还是本就没有才返回的 null(空)  值。也就是说,产生的歧义不能被  证  伪,

3、作者回复

对于 ConcurrentHashMap 不允许插入 null 值的问题,有人问过 ConcurrentHashMap 的作者 Doug Lea,以下是他回复的邮件内容:


The main reason that nulls aren't allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can't be accommodated. The main one is that if map.get(key) returns null, you can't detect whether the key explicitly maps to null vs the key isn't mapped.

In a non-concurrent map, you can check this via map.contains(key),but in a concurrent one, the map might have changed between calls.

Further digressing: I personally think that allowing

nulls in Maps (also Sets) is an open invitation for programs

to contain errors that remain undetected until

they break at just the wrong time. (Whether to allow nulls even

in non-concurrent Maps/Sets is one of the few design issues surrounding

Collections that Josh Bloch and I have long disagreed about.)

It is very difficult to check for null keys and values

in my entire application .

Would it be easier to declare somewhere

static final Object NULL = new Object();

and replace all use of nulls in uses of maps with NULL?

-Doug


以上信件的主要意思是,Doug Lea 认为这样设计最主要的原因是:不容忍在并发场景下出现歧义!

4、总结

ConcurrentHashMap在源码中加入不允许插入 null (空) 值的设计,主要目的是为了防止并发场景下的歧义问题。

以上就是我对关于ConcurrentHashMap为什么不允许插入 null (空) 值的解答,听懂的小伙伴,请关注点个赞,下次不迷路。

相关文章
|
安全 Java
【Java面试】ConcurrentHashMap的key为什么不允许为null?
【Java面试】ConcurrentHashMap的key为什么不允许为null?
368 0
|
2月前
|
存储 开发者
HashMap和Hashtable的key和value可以为null吗,ConcurrentHashMap呢
HashMap的key可以为null,value也可以为null;Hashtable的key不允许为null,value也不能为null;ConcurrentHashMap的key不允许为null
|
7月前
|
存储 C++
为什么HashMap的键值可以为null,而ConcurrentHashMap不行?
为什么HashMap的键值可以为null,而ConcurrentHashMap不行?
94 1
|
安全 Java
面试突击19:为什么ConcurrentHashMap不允许插入null值?
在 Java 语言中,ConcurrentHashMap 和 Hashtable 这些线程安全的集合是不允许 key 或 value 插入 null 值的,而 HashMap 又允许 key 或 value 插入 null 值,这到底是为什么呢?
549 0
面试突击19:为什么ConcurrentHashMap不允许插入null值?
|
7月前
|
机器学习/深度学习 SQL 关系型数据库
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
91 0
|
7月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用合集之从MySQL同步数据到Doris时,历史数据时间字段显示为null,而增量数据部分的时间类型字段正常显示的原因是什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
7月前
|
SQL 关系型数据库 MySQL
python在mysql中插入或者更新null空值
这段代码是Python操作MySQL数据库的示例。它执行SQL查询从表`a_kuakao_school`中选取`id`,`university_id`和`grade`,当`university_id`大于0时按升序排列。然后遍历结果,根据`row[4]`的值决定`grade`是否为`NULL`。若不为空,`grade`被格式化为字符串;否则,设为`NULL`。接着构造UPDATE语句更新`university`表中对应`id`的`grade`值,并提交事务。重要的是,字符串`NULL`不应加引号,否则更新会失败。
171 2
|
4月前
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 IS NULL
【8月更文挑战第12天】
670 0
在 MySQL 中使用 IS NULL
|
4月前
|
SQL 关系型数据库 MySQL
mysql不等于<>取特定值反向条件的时候字段有null值或空值读取不到数据
对于数据库开发的专业人士来说,理解NULL的特性并知道如何正确地在查询中处理它们是非常重要的。以上所介绍的技巧和实例可以帮助你更精准地执行数据库查询,并确保数据的完整性和准确性。在编写代码和设计数据库结构时,牢记这些细节将有助于你避免许多常见的错误,提高数据库应用的质量与性能。
144 0
|
5月前
|
SQL 存储 索引
MySQL设计规约问题之为什么应该把字段定义为NOT NULL并且提供默认值
MySQL设计规约问题之为什么应该把字段定义为NOT NULL并且提供默认值
下一篇
DataWorks