应优先用Objects.requireNonNull()在方法入口校验非空参数,配合@NotNull注解和IDE预警;对可能为空的返回值用Optional封装并链式处理;警惕自动拆箱和字符串拼接隐式调用引发的NPE。

用 Objects.requireNonNull() 主动拦截 null
空指针异常(NullPointerException)多数发生在你默认参数或返回值非空,但实际传入了 null。与其等运行时崩在某个深层调用里,不如在方法入口就明确契约。Objects.requireNonNull() 是最轻量、最直观的防御手段。
- 它会在值为
null时立即抛出带消息的NullPointerException,堆栈指向调用处,而非下游某行.toString() - 适合校验方法参数:比如
public void process(User user) { Objects.requireNonNull(user, "user must not be null"); ... } - 不建议滥用在循环体内或高频路径上——虽开销极小,但语义上它表示“这是契约性检查”,不是流程控制
用 Optional 表达“可能为空”的语义
Optional 不是用来“避免 NPE”的银弹,而是帮你把“是否为空”从隐式状态变成显式类型。它强制调用方思考分支逻辑,而不是靠运气躲过 null。
- 只对**方法返回值**有意义:比如
Optional,比返回findUserById(Long id) User或null更清晰 - 不要用
Optional包装字段、参数或集合元素——这违背设计初衷,且会增加 GC 压力 - 慎用
Optional.get():它和直接解引用一样危险;优先用ifPresent()、orElse()、map()等安全链式操作
用 IDE 和注解提前暴露潜在问题
很多 NPE 其实是编译期就能发现的逻辑疏漏。现代 IDE(如 IntelliJ)配合注解能大幅降低漏网之鱼。
- 在参数/字段上加
@NotNull(JetBrains)或@NonNull(Checker Framework),IDE 会在你传null时标黄警告 - 启用编译器的
-Xlint:unchecked和-Xlint:cast,部分 NPE 相关隐患会被捕获 - 注意:注解本身不运行时生效,它依赖工具链;别以为加了
@NotNull就不用requireNonNull()了
警惕自动拆箱和字符串拼接里的隐式调用
这两类场景最常“悄无声息”触发 NPE,因为表面看没有点号调用,容易被忽略。
立即学习“Java免费学习笔记(深入)”;
- 自动拆箱:
Integer i = null; int j = i; // NPE here—— 只要涉及int/boolean等基本类型赋值,就可能触发 - 字符串拼接:
String s = null; String msg = "value: " + s; // OK,但s.toString()或s.length()在拼接前被手动调用就会崩 - 日志中用占位符(如 SLF4J 的
log.debug("user={}", user))比字符串拼接更安全,避免提前触发toString()
requireNonNull()。这时候得靠单元测试覆盖边界输入,以及日志里多打几行 Objects.toString(x, "null") 这类防御性输出。










