在Java中集合是否允许存null_Java不同集合支持情况解析

ArrayList和LinkedList可存null;HashMap允一个null键和多个null值,Hashtable完全禁止;HashSet和LinkedHashSet允许null,TreeSet无参构造时禁止null,自定义Comparator可支持;ConcurrentHashMap禁止null键值,CopyOnWriteArrayList允许null。

ArrayList 和 LinkedList 能否存 null

可以,ArrayListLinkedList 都允许任意数量的 null 元素。它们底层基于数组或链表实现,不校验元素是否为 null

常见错误现象:调用 get() 返回 null 后直接链式调用方法(如 list.get(i).toString()),触发 NullPointerException —— 这不是集合本身的问题,而是业务逻辑未判空。

  • add(null) 正常执行,不会抛异常
  • contains(null) 返回 true(如果确实添加过)
  • indexOf(null) 返回第一个 null 的下标

HashMap 和 Hashtable 对 null 的处理差异

HashMap 允许一个 null 键和任意多个 null 值;Hashtable 则完全禁止 null 键和 null 值,否则立即抛 NullPointerException

原因在于 Hashtable 是遗留类,设计时强调线程安全与严格校验;HashMap 更注重灵活性与性能,把判空责任交给使用者。

  • new HashMap().put(null, "a") ✅ 成功
  • new Hashtable().put(null, "a") ❌ 抛 NullPointerException
  • new HashMap().put("k", null) ✅ 成功
  • new Hashtable().put("k", null) ❌ 同样抛异常

HashSet、TreeSet、LinkedHashSet 的 null 支持边界

HashSetLinkedHashSet 允许存 null(因为底层是 HashMapnull 作为 key 存入);TreeSet 是否允许取决于其构造方式:

  • 无参构造:使用自然排序,add(null) 直接抛 NullPointerException(因为 null.compareTo(...) 不合法)
  • 传入自定义 Comparator:若该比较器能安全处理 null(例如用 Comparator.nullsFirst()),则可存 null

注意:TreeSet 中即使允许 null,也只能有一个 —— 因为它按“相等”逻辑去重,而 nullnull 视为重复。

ConcurrentHashMap 和 CopyOnWriteArrayList 的 null 约束

ConcurrentHashMap 明确禁止 null 键和 null 值,否则在 put() 时就抛 NullPointerExceptionCopyOnWriteArrayList 允许 null,行为同 ArrayList

这是并发容器的主动防御设计:ConcurrentHashMap 内部大量依赖 key.hashCode()key.equals(),而 null 会导致这些调用失败或语义模糊,所以从源头拦截。

  • new ConcurrentHashMap().put(null, "v") ❌ 立即报错
  • new CopyOnWriteArrayList().add(null) ✅ 允许
  • Collections.synchronizedSet(new HashSet()) 允许 null(同步包装不改变底层行为)
Map map = new ConcurrentHashMap<>();
// 下面这行会抛 NullPointerException,不是运行时偶然,而是设计强制
map.put(null, "value"); // java.lang.NullPointerException
实际编码中,最容易被忽略的是 TreeSet 的自然排序场景下对 null 的静默拒绝,以及 ConcurrentHashMapnull 的零容忍 —— 它们不像 HashMap 那样“宽容”,出错位置也更靠前。