空指针异常是运行时因解引用null触发的崩溃,非编译错误;避免关键在于设计、编码、工具三层面主动拦截:入口参数用objects.requirenonnull校验,返回值用optional显式表达可选性,字符串/集合操作先判空,辅以@nonnull注解和静态分析工具预警。

空指针异常(NullPointerException)不是编译错误,而是在运行时因解引用 null 值触发的崩溃。它不提前报错,却常导致服务中断、排查困难。避免的关键不是事后 try-catch,而是从设计、编码和工具三层面主动拦截。
入口参数必须校验
方法或构造器接收的对象参数,只要后续会调用其方法或访问字段,就该在开头强制检查:
- 用
Objects.requireNonNull(param, "param must not be null")替代手写if (param == null)—— 消息清晰、堆栈精准指向调用处 - 适用于 public 方法入参、构造函数依赖项(如
UserService(UserRepository repo))、不可变字段初始化 - 不用于返回值判断或业务逻辑中合法的可选场景(比如“查不到用户”本就是正常分支)
返回值用 Optional 显式表达可选性
当一个方法的结果天然可能不存在(如数据库查询、配置读取、缓存获取),返回 null 是隐式且危险的。改用 Optional<t></t> 可让调用方无法忽略空值路径:
- DAO 层示例:
public Optional<user> findUserById(Long id)</user>,而非public User findUserById(Long id) - 调用时优先用
.orElse()、.orElseGet()或.ifPresent(),避免裸调.get() - 禁止将
Optional作为字段、方法参数或集合元素——它只应出现在返回值位置
字符串和集合操作先判空再使用
很多 NPE 来自“以为安全”的操作,比如 str.isEmpty() 或 list.size(),但前提是 str 和 list 本身不为 null:
- 字符串比较统一用字面量在前:
"admin".equals(role),而不是role.equals("admin") - 判空推荐组合写法:
str != null && !str.trim().isEmpty(),或引入 Apache Commons Lang 的StringUtils.isNotBlank(str) - 集合返回一律用空实例:
return Collections.emptyList(),而不是return null;调用方可直接遍历,无需额外判空
借助注解和静态检查提前预警
靠人眼识别空值流容易遗漏。用工具把约束“写进代码”更可靠:
- 在参数、返回值、字段上标注
@NonNull(JetBrains)或@Nullable,IDE(如 IntelliJ)会在不安全解引用处标黄甚至报错 - Maven 中集成 SpotBugs 或 ErrorProne,自动扫描
== null误用、未处理的Optional、冗余判空等隐患 - Lombok 的
@RequiredArgsConstructor(onConstructor_ = {@NonNull})可自动生成构造器中的非空校验逻辑
不复杂但容易忽略:空值不是 bug,而是契约缺失。每次写方法签名、定义返回类型、接收外部数据时,多问一句“它可能为 null 吗?我是否明确表达了这个语义?”——这才是预防 NPE 最稳的一环。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











