HashMap允许key和value为null,ConcurrentHashMap禁止;ArrayList/LinkedList允许null元素;TreeSet/TreeMap因比较机制排斥null;Arrays.asList()返回的列表不支持add/remove。

HashMap 允许 key 和 value 都为 null
这是最常被误用的一点:HashMap 本身不抛 NullPointerException,哪怕你 put null 作为 key 或 value。它内部用 hash(0) 处理 null key,把 entry 放到数组索引 0 的位置。
但要注意:ConcurrentHashMap 完全不允许 null key 或 value —— 任何一次 put(null, "v") 都会立即抛 NullPointerException。
-
HashMap.put(null, "a")✅ 合法,后续get(null)返回"a" -
ConcurrentHashMap.put(null, "a")❌ 运行时报错 -
HashMap.get(null)返回null时,无法区分“key 不存在”还是“key 存在但 value 是 null”——必须用containsKey(null)辅助判断
ArrayList 和 LinkedList 允许存 null 元素
这两个 List 实现对 null 完全开放:add(null)、set(0, null)、get(i) 返回 null 都是合法行为。它们不校验元素是否为 null,也不在迭代时跳过。
但副作用明显:一旦混入 null,调用 stream().map(...).collect(...) 或 forEach(System.out::println) 就可能触发空指针;indexOf(null) 也能正常返回下标。
立即学习“Java免费学习笔记(深入)”;
-
list.add(null)✅ 合法,list.size()会 +1 -
list.indexOf(null)返回第一个null的索引(如 2) -
list.remove(null)删除的是第一个值为null的元素(不是按索引删) -
Collections.unmodifiableList(list)不改变null的可存性,只是禁止修改结构
TreeSet / TreeMap 要求元素/键可比较,天然排斥 null
TreeSet 和 TreeMap 依赖 Comparable.compareTo() 或 Comparator.compare() 排序,而 null 在比较时必然抛 NullPointerException。哪怕你用自定义 Comparator,只要没显式处理 null,一碰就崩。
TreeSetset = new TreeSet<>(); set.add(null); // 运行时报:NullPointerException
- 除非你写一个容忍
null的Comparator,比如(a, b) -> { if (a == null) return -1; if (b == null) return 1; return a.compareTo(b); } -
TreeSet的contains(null)也会报错,不是返回false -
HashSet和LinkedHashSet没这个问题——它们不比较,只算 hash,null的 hash 值固定为 0
Arrays.asList() 返回的 List 不支持 null 添加
Arrays.asList(new String[]{"a", "b"}) 返回的是 Arrays$ArrayList(非 java.util.ArrayList),它是固定大小的视图。虽然允许已有元素为 null(如 Arrays.asList("a", null)),但调用 add() 或 remove() 会直接抛 UnsupportedOperationException。
更隐蔽的是:这个 list 的 set(i, null) 是允许的,但 add(null) 不行 —— 很多人误以为“能设 null 就能加 null”,结果线上炸了。
-
Arrays.asList("a").set(0, null)✅ 成功,list 变成[null] -
Arrays.asList("a").add(null)❌ 抛UnsupportedOperationException - 如果需要可变集合,必须包装:
new ArrayList(Arrays.asList(...))
null 在集合里的语义往往模糊——是缺失值?未初始化?还是业务上有效的空状态?Java 集合本身不做价值判断,只做行为约束。最容易翻车的,是把 HashMap 当成安全兜底,却忘了下游代码没做 containsKey 校验;或者在 TreeSet 里传进带 null 的对象,连构造都过不去。










