Objects.requireNonNull()的核心用途是在方法入口、构造器或关键状态初始化时立即检查非空契约,传入null即抛带提示的NullPointerException;它不预防空指针,也不修复空值,仅作契约断言。

Objects.requireNonNull() 的核心用途和触发时机
它不是用来“预防空指针”的防御性工具,而是用来在参数/状态明显不该为 null 时,**立刻失败并给出清晰线索**。一旦传入 null,它会立即抛出 NullPointerException,且异常消息里包含你传的提示字符串(如果提供了的话)。
常见误用是把它塞进业务逻辑中间做“兜底”,比如在方法体快结束时才检查某个计算结果——这反而掩盖了真正出问题的位置。它该出现在方法入口、构造器参数赋值、或关键状态初始化之后。
什么时候该用 requireNonNull() 而不是 if (x == null) throw ...
两者语义一致,但 Objects.requireNonNull() 更简洁、更符合 JDK 标准实践,且能利用 JVM 对其的内联优化(JDK 9+)。更重要的是:它明确表达了“此处必须非空”的契约意图,比手写 if 更易被静态分析工具识别。
- 构造器中检查不可变字段:
this.name = Objects.requireNonNull(name, "name must not be null"); - public 方法参数校验(尤其当该方法不处理
null语义时) - 接收 Optional 返回值后进一步断言:
Objects.requireNonNull(opt.get(), "expected value present")(注意:慎用,通常应先用isPresent()或orElseThrow())
requireNonNull() 的重载差异与陷阱
有两个常用重载:
Objects.requireNonNull(T obj) —— 只抛默认异常,堆栈里看不到上下文;
Objects.requireNonNull(T obj, String message) —— 推荐始终使用这个,message 会被放进 NullPointerException 的 detailMessage 字段,调试时直接可见。
容易踩的坑:
- 传入的
message本身为null:会触发二次 NPE,且无提示——Objects.requireNonNull(null, null)抛的是“Cannot invoke \"String.toString()\" because \"s\" is null” - 在日志或 toString() 中间接调用它:比如
log.info("user: {}", Objects.requireNonNull(user)),一旦user为空,日志还没打就崩了 - 误以为它会“修复”空值:它不做任何转换或默认值填充,只检查+抛异常
替代方案与性能提醒
如果你需要默认值而非报错,别硬套 requireNonNull(),改用 Objects.requireNonNullElse() 或三元表达式。
性能上,它几乎无开销(HotSpot 会内联),但频繁在循环内调用仍属可疑设计——说明空值本不该出现在那个上下文中。
真正容易被忽略的是:它只检查引用是否为 null,不检查集合是否为空、字符串是否空白、数组是否长度为 0。这些得靠 Collection.isEmpty()、String.isBlank() 等单独判断。

















