在集合中哪些可以为null,哪些不能为null;Java 集合中 null 值允许情况总结与记忆技巧

Java 集合中 null 值允许情况总结与记忆技巧

一、核心集合对 null 的支持情况

集合类型 Key 是否可为 null Value 是否可为 null 原因/备注
HashMap ✅ 是 ✅ 是 对 null key 有特殊处理(存放在数组第 0 个位置)
LinkedHashMap ✅ 是 ✅ 是 继承自 HashMap
TreeMap ❌ 否 ✅ 是 依赖 Comparator/Comparable,可能抛 NullPointerException
Hashtable ❌ 否 ❌ 否 设计较早,未做 null 处理(直接抛 NullPointerException
ConcurrentHashMap ❌ 否 ❌ 否 并发场景下 null 会歧义(如 get(key)返回null时无法区分是不存在还是值为null)
HashSet ✅ 是 - 底层是 HashMap,value 固定为 PRESENT 对象
TreeSet ❌ 否 - 底层是 TreeMap
ArrayList - ✅ 是 列表允许存储 null
LinkedList - ✅ 是 同 ArrayList
ArrayDeque - ❌ 否 作为队列/栈使用时,null 会干扰 poll() 等方法语义

二、记忆技巧(口诀)

1. Map 系列记忆法

"哈林可以,树并不行"

  • 哈(HashMap)、林(LinkedHashMap):允许 null key 和 null value

  • 树(TreeMap)、并(ConcurrentHashMap):不允许 null key

  • Hashtable:老古董,什么都不让用(联想:老顽固)

2. Set 系列记忆法

"Hash 随意,Tree 挑剔"

  • HashSet:允许 null(因为底层是 HashMap)

  • TreeSet:不允许 null(因为底层是 TreeMap)

3. List/Queue 记忆法

"列表宽容,队列严格"

  • ArrayList/LinkedList:允许 null

  • ArrayDeque:不允许 null(避免 poll() 歧义)


三、技术原因深度解析

1. 为什么 HashMap 允许 null?

  • 特殊处理:将 null key 的哈希值固定为 0,存储在数组第 0 个桶。

  • 代码示例(HashMap 的 put 方法):

    java

if (key == null) {
    return putForNullKey(value); // 特殊处理
}

2. 为什么 TreeMap 不允许 null key?

  • 排序依赖:必须调用 compareTo() 或 compare(),null 无法比较。

  • 代码示例

    java

// 如果 comparator 为 null,使用自然排序
Comparator<? super K> cpr = comparator;
if (cpr == null) {
    Comparable<? super K> k = (Comparable<? super K>) key; // 这里可能抛 NPE
}

3. 为什么 ConcurrentHashMap 完全禁止 null?

  • 并发歧义

    • 如果允许 null value,无法区分 map.get(key)==null 是"不存在该key"还是"该key的值为null"。

    • 作者 Doug Lea 的解释:"在非并发Map中,可以通过containsKey检查,但并发场景下检查与操作不是原子的"


四、面试高频问题

1. HashMap 如何处理 null key?

  • 存储在数组第 0 个桶(table[0]),哈希值固定为 0。

2. 哪些集合的迭代器可能抛 NullPointerException?

  • TreeMap/TreeSet:如果元素未实现 Comparable 或 Comparator 未处理 null。

3. 如何让 TreeMap 支持 null key?

  • 自定义 Comparator 处理 null:

    java

TreeMap<String, Integer> map = new TreeMap<>((a, b) -> {
    if (a == null) return -1; // 定义 null 的排序规则
    if (b == null) return 1;
    return a.compareTo(b);
});

五、总结表(速记版)

集合类型 Key Value 记忆口诀
HashMap 哈林可以
LinkedHashMap 哈林可以
TreeMap 树并不行(Tree不行)
Hashtable 老古董
ConcurrentHashMap 树并不行(Concurrent不行)
HashSet - Hash 随意
TreeSet - Tree 挑剔
ArrayList - 列表宽容
ArrayDeque - 队列严格

掌握这些规则和记忆技巧,面试时再也不用担心 null 值问题!