集合空指针异常主因是集合变量为null或元素为null被直接调用;需分两层排查:先判集合引用非null,再过滤/校验元素;推荐返回空集合、用objects.requirenonnull、stream.filter(objects::nonnull)及注解工具防控。

集合类空指针异常(NullPointerException)大多不是集合本身“为空”,而是集合变量为 null,或集合中元素为 null 却被直接调用方法。排查处理要分两层:先看集合引用是否为 null,再看遍历时的元素是否可安全使用。
检查集合变量是否为 null
这是最常见也最容易忽略的一环。比如 List<string> list = null;</string>,后续直接调用 list.size() 或 list.forEach(...) 就会立即抛出 NPE。
- 在使用前加判空:
if (list != null) { ... } - 初始化时优先返回空集合而非
null:例如工具方法应返回Collections.emptyList()或new ArrayList(),而不是null - 用
Objects.requireNonNull(list, "list must not be null")在入口处强制校验,提前暴露问题
过滤集合中的 null 元素再操作
即使集合本身不为 null,里面存了 null 值(如 Arrays.asList("a", null, "b")),遍历时调用 item.toString() 或 item.length() 同样会崩。
- 传统方式:遍历前手动过滤
null:for (String s : list) { if (s != null) { ... } } - Stream 方式更简洁:
list.stream().filter(Objects::nonNull).forEach(...) - 若需保留原始结构但避免 NPE,可用
Optional.ofNullable(item).map(String::length).orElse(0)
注意集合操作方法的隐性要求
有些集合方法对参数敏感,比如 addAll(null)、putAll(null)、containsAll(null) 都会直接抛 NPE,不是因为接收方为空,而是传入参数为 null。
- 调用前确认参数非空,例如:
if (otherList != null) targetList.addAll(otherList); - Map 的
get(key)返回null是正常行为,但后续不能直接链式调用,应先判断:User u = map.get(id); if (u != null) u.getName(); - 避免
list.get(0)这类越界+空值双重风险操作,改用list.isEmpty() ? null : list.get(0)
借助工具和规范从源头减少风险
靠每次手写判空容易遗漏,建议结合编码习惯与工具加固:
- 用
@NonNull/@Nullable注解(如 JetBrains 或 Lombok 提供)配合 IDE 提示,在编译期预警潜在空值路径 - 第三方库返回集合时,优先选用明确声明“never returns null”的 API(如 Guava 的
ImmutableList.of()、MyBatis-Plus 的list()默认返回空列表) - 单元测试覆盖边界场景:包括空集合、含
null元素的集合、方法返回null的模拟情况











