objects.requirenonnull 能防 npe 是因为它在 null 传入时立即抛出带提示的 nullpointerexception,提前暴露问题而非掩盖;适用于方法入口和构造函数的参数校验,返回原对象支持链式调用,但不可滥用或替代业务逻辑对 null 的处理。

Objects.requireNonNull 为什么能防 NPE 而不是“假装没空”
Objects.requireNonNull 不是让 null 变成有效对象,而是立刻暴露问题:只要传入 null,它就抛出 NullPointerException,并附带可读的提示信息。这比等后续调用 .toString() 或 .length() 时才崩更早、更明确。
它适合用在方法入口、构造函数参数校验这类“信任边界”上——你希望调用方负责传非空,而不是自己兜底处理 null。
常见错误现象:
- 把 requireNonNull 放在逻辑中间(比如循环里反复校验同一个变量),纯属冗余;
- 误以为加了它就能“避免崩溃”,其实只是把崩溃点前移,并未消除 null 来源;
- 忘记传自定义提示消息,导致报错时只看到 "null",无法定位是哪个参数出问题。
- 推荐写法:
Objects.requireNonNull(str, "str must not be null") - 构造函数中建议全量校验:
this.name = Objects.requireNonNull(name, "name"); - 不要对已知可能为
null的字段调用它(比如数据库查不到返回的null),那是业务逻辑该处理的,不是这里该炸的
和 if (x == null) throw new NPE() 有啥实际区别
语义一样,但 Objects.requireNonNull 更轻、更统一、更易维护。
使用场景差异明显:
- 手写 if 判断容易漏掉消息,或写成 IllegalArgumentException 混淆语义;
- 多参数校验时,手写一堆 if 显得啰嗦,而 requireNonNull 可配合 IDE 快捷键批量插入;
- JDK 自带实现做了简单优化(比如空消息字符串直接复用常量),虽无性能瓶颈,但至少不拖后腿。
- 参数差异:它有两个重载 ——
requireNonNull(T)和requireNonNull(T, String),后者才是生产环境推荐用的 - 注意返回值:它返回的是原对象(泛型
T),所以能链式使用:new File(Objects.requireNonNull(path)) - 别把它当“防御性编程万金油”——如果业务允许
null(如可选配置项),硬加会破坏契约
替代方案对比:Optional、@NonNull、Lombok @NonNull
Optional 是表达“可能为空”的语义容器,不是空值校验工具;@NonNull 注解(JSR-305 或 JetBrains)只起静态检查作用,运行时不生效;Lombok 的 @NonNull 实际就是在构造器/方法开头插一段 requireNonNull,本质相同但侵入编译流程。
立即学习“Java免费学习笔记(深入)”;
容易踩的坑:
- 用 Optional.of(null) 直接炸,而 Optional.ofNullable(null) 才安全,新手常混淆;
- IDE 或 FindBugs 的 @NonNull 检查依赖注解处理器,没配好就等于没写;
- Lombok 的 @NonNull 对局部变量无效,且生成的字节码里看不到校验逻辑,调试时容易懵。
- 真实建议:对外 API 参数强制非空 → 用
Objects.requireNonNull; - 内部数据流转可能为空 → 用
Optional明确语义; - 团队已有 Lombok 且接受编译期注入 →
@NonNull可省几行,但别指望它比手写requireNonNull更可靠
Android 开发里要注意兼容性问题
Objects.requireNonNull 从 Android API 19(KitKat)开始才有,低于这个版本会 NoClassDefFoundError。如果你的 minSdk
常见错误现象:
- 本地测试跑得好好的,低版本真机一运行就崩在第一行 requireNonNull;
- Gradle 启用了 desugaring 但没开 coreLibraryDesugaringEnabled true,依然报错。
- 解决方案:启用 desugar(AGP 4.0+ 默认支持),并在
build.gradle加:coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' - 或者降级写法:
if (obj == null) throw new NullPointerException("obj");,虽然丑,但稳 - 别信 “API 19 很老了,不用管”——国内仍有大量 API 16–18 的设备在灰度场景中存活
事情说清了就结束。真正难的不是加一行 requireNonNull,而是判断哪里该加、哪里不该加,以及当它炸了之后,你能不能顺着堆栈一眼看出是上游哪次调用没守约。









