Objects.requireNonNull 不能捕获 NullPointerException,因其设计目的是主动暴露空值问题而非兜底处理;它属于断言式检查,适用于方法入口等明确要求非空的场景。

Objects.requireNonNull 为什么不能直接捕获 NullPointerException
调用 Objects.requireNonNull 的目的不是为了“处理”空值,而是主动暴露问题:它在参数为 null 时立即抛出 NullPointerException,不给后续逻辑留隐患。你无法也不该用 try-catch 包裹它来“兜底”——这违背了它的设计意图。它属于防御性编程中的断言式检查,适用于方法入口、构造函数等明确要求非空的场景。
常见错误现象:
– 在 catch (NullPointerException e) 里试图恢复逻辑,结果掩盖了本该提前暴露的 bug
– 把它放在可能被频繁调用的循环内部,导致性能无谓下降(虽然开销小,但语义错位)
如何传入自定义异常消息避免排查困难
不带消息的 Objects.requireNonNull(obj) 抛出的异常只有堆栈,没有上下文。一旦多个参数都做检查,根本分不清是哪个变量为空。必须用双参数重载版本:
public static <T> T requireNonNull(T obj, String message)
使用建议:
- 消息中明确写出变量名,例如
"name must not be null",而不是模糊的"Parameter is null" - 如果涉及嵌套对象字段,可写成
"user.getProfile() must not be null",但更推荐对user和user.getProfile()分开校验 - 避免拼接运行时值(如
"id=" + id),除非该值本身对定位问题关键;否则增加字符串开销且日志冗余
和 if (obj == null) throw new NullPointerException() 有什么区别
语义完全等价,但 Objects.requireNonNull 更简洁、统一,且 JVM 对其有少量优化(如 JIT 可能内联)。更重要的是,它传递了明确的协作信号:这是标准库认可的非空契约表达方式。
实际差异点:
- 字节码更短,可读性更高,尤其在多参数检查时(对比一连串
if) - 某些静态分析工具(如 IntelliJ、ErrorProne)能识别
requireNonNull并推导出后续代码中该变量非空,提供更好的空值提示 - 不推荐混用:同一项目里既写
if (x == null) throw ...又用requireNonNull,会降低代码一致性
哪些地方不该用 Objects.requireNonNull
它只适合“契约强制非空”的场景,不是万能空值处理器:
- 数据库查询结果可能为空(如
Optional<user></user>或null),此时应先判断再决定是否抛异常,而不是无脑requireNonNull - HTTP 请求参数、配置项这类外部输入,更适合用业务异常(如
IllegalArgumentException)并附带用户友好的提示,而非NullPointerException - 流式操作中(如
stream().map(...).filter(...)),不要对中间结果逐个requireNonNull;应在源头或终端消费处集中处理 - 泛型类型擦除后无法校验的场景(如
List<string></string>内部元素是否为空),requireNonNull完全无效
真正容易被忽略的是:它只检查引用本身是否为 null,不检查字符串是否为空串、集合是否为空、数组长度是否为 0——这些需要额外判断,别指望它一并解决。

















