支持contains(null)的集合包括arraylist、linkedlist、hashset、linkedhashset及hashmap(含containskey(null));treeset、treemap、concurrentskiplistset/map等基于比较器的集合调用contains(null)会立即抛nullpointerexception。

Java 中 contains(Object o) 方法对 null 的处理,取决于具体集合实现类的底层逻辑,不是统一行为——有的能安全接受 null 作参数,有的直接抛 NullPointerException;同样,集合里能否存 null,也因类而异。
哪些集合支持 contains(null)?
多数基于哈希或线性查找的集合允许调用 contains(null),只要它们内部使用 equals() 判断相等性(而 null.equals(x) 是合法的 false):
-
ArrayList / LinkedList:支持
contains(null),若列表中确实 add 过null,就返回true -
HashSet / LinkedHashSet / HashMap(value 或 key 为 null 时):支持
contains(null),HashMap.containsKey(null)也合法 -
ConcurrentHashMap:不支持
containsKey(null)或containsValue(null)—— 调用即抛异常,因为其设计禁止null键值
哪些集合调用 contains(null) 会崩溃?
所有依赖 compareTo() 或 Comparator.compare() 的有序集合,无法处理 null 参数:
-
TreeSet:调用
contains(null)立即抛NullPointerException(内部触发null.compareTo(x)) -
TreeMap:同理,
containsKey(null)或containsValue(null)均不可行 -
ConcurrentSkipListSet / ConcurrentSkipListMap:行为与 TreeSet/TreeMap 一致,
null参与比较即失败
存 null 和查 null 是两回事
一个集合是否允许 add(null),和它能否安全执行 contains(null) 并不总是一致:
-
ArrayList允许add(null),也支持contains(null) -
ArrayDeque不允许add(null)(构造时不会报错,但首次add(null)就抛异常),自然也不支持contains(null) -
TreeSet即使没存过null,只要调用contains(null)就崩——根本不需要先 add
怎么写才不容易出错?
避免在运行时突然炸掉,关键不是记住每种集合的规则,而是建立防御习惯:
- 对外部输入(如数据库字段、HTTP 参数)做判空,再进集合,比如
if (id != null) set.add(id); - 不确定集合类型时,查
null前先用isEmpty()或size() > 0辅助判断,不盲目调用contains(null) - 替换集合实现(比如从
HashSet换成TreeSet)时,必须检查所有涉及null的add和contains调用点 - 业务上真需要表达“无值”,优先用
Optional.empty()、空集合或枚举,而不是靠null打哑谜
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











