ConcurrentHashMap 和 HashMap 中key或value的 null 值问题详解
·
ConcurrentHashMap 和 HashMap 对 null 值的处理
在 Java 集合框架中,ConcurrentHashMap 和 HashMap 对 null 值的处理有明显差异,这是面试和开发中常被问到的核心知识点。本文将详细拆解两者的区别及背后原因。
1. 核心结论
- ConcurrentHashMap:不允许 key 或 value 为
null。 - HashMap:允许 key(最多一个)和 value 为
null。
2. HashMap 中 null 的具体规则
① key 只能有一个 null
HashMap允许put(null, value),但只能存一次;- 如果再次执行
put(null, anotherValue),会覆盖之前null对应的 value(因为null作为 key 是唯一的); - 底层实现:key 为
null的键值对会固定放在第 0 个桶(null的 hash 值为 0)。
② value 可以有多个 null
- 不同的 key 可对应
value=null,例如:map.put("a", null); map.put("b", null); map.put("c", null); - 上述键值对可共存,不会互相覆盖。
3. 为什么 ConcurrentHashMap 不允许 null?
① 二义性问题(核心原因)
调用 map.get(key) 返回 null 时,并发场景下无法区分两种情况:
- 该 key 对应的 value 本身就是
null; - 该 key 根本不存在于 map 中。
单线程 HashMap 可通过 containsKey(key) 二次判断消除歧义,但在并发环境下,get 和 containsKey 这两个操作并非原子操作。如果强行将它们组合使用,就必须加锁,这违背了 ConcurrentHashMap 设计的初衷——在不加锁的前提下保证并发安全。因此,二义性问题在并发场景下无法被可靠地消除,所以 ConcurrentHashMap 直接禁止了 key 和 value 为 null。
② 空指针异常(辅助原因)
ConcurrentHashMap 的内部方法(如 hash(key))会直接操作 key,传入 null 会抛出 NullPointerException,这是快速失败的安全机制,避免后续并发 bug 难以排查。
4. 为什么 HashMap 允许 null?
HashMap 为单线程环境设计,操作是原子性的,无并发修改问题:
- 调用
get(key)返回null时,可紧接着调用containsKey(key)确认:- 返回
true→ value 是null; - 返回
false→ key 不存在。
- 返回
- 单线程下两次调用连续执行,无其他线程干扰,结果可靠。
5. 一句话总结
- ConcurrentHashMap:为并发安全牺牲
null灵活性,避免二义性问题; - HashMap:为单线程便利性允许
null,key 为null固定在第 0 桶且仅一个,可通过二次判断消除歧义。
注意:实际开发中应尽量避免将 null 作为 key/value,减少代码歧义性和潜在 bug。
更多推荐



所有评论(0)