Objects.requireNonNull并非万能解药,它仅适用于绝对不可为null的边界输入;对合法语义空应使用Optional封装或明确文档标注,而非强制抛异常。

Java中Objects.requireNonNull为何不是万能解药
它确实能快速暴露null,但前提是调用方主动加——这在深层调用链、第三方库返回值、或配置未加载完成的场景下根本不可控。比如service.findUser(id)返回null,你没在入口校验,下游直接user.getName()就NPE了。
更关键的是,它把“空值处理逻辑”推给了调用方,而实际业务里,很多null是合法状态(如用户未填地址),强制抛异常反而破坏流程。真正要做的,是区分「非法空」和「语义空」。
-
requireNonNull适合构造函数参数、必填配置项等绝对不允许为null的边界输入 - 对可能为空的返回值,优先用
Optional封装,而非裸null - 若必须返回
null(如遗留接口),应在Javadoc明确标注@return may be null
用Optional替代null返回值的实操陷阱
Optional本意是让空值显式化,但滥用会导致嵌套地狱或误用get()重蹈NPE覆辙。例如userRepo.findById(123).get().getProfile().getEmail()——只要中间任一环节是Optional.empty(),get()立刻炸。
正确姿势是链式消费:用map、flatMap、orElse把逻辑写在Optional内部,而不是把它当容器取出来再操作。
立即学习“Java免费学习笔记(深入)”;
- 不要用
Optional包装集合或数组(该用Collections.emptyList()) - 不要将
Optional作为方法参数或字段(违背其设计初衷) - 数据库查询结果为空时,用
Optional.ofNullable(result)包装,而非直接返回null
静态工具类Objects.nonNull和Objects.isNull的真实用途
它们只是简洁的判空工具,不解决根本问题。常见误用是写成if (Objects.nonNull(user)) { user.getName(); }——这跟if (user != null)没区别,只是多了一层方法调用开销。
它的价值在于配合Stream或Lambda:比如过滤掉空值list.stream().filter(Objects::nonNull).map(User::getName),或在computeIfAbsent中做键存在性判断。
- 避免在高频循环里反复调用
nonNull,JVM虽会内联,但语义清晰更重要 - 与
StringUtils.isEmpty(Apache Commons)或Strings.isNullOrEmpty(Guava)配合处理字符串空值 - 注意
Objects.isNull(x)等价于x == null,不是Objects.equals(x, null)
Lombok的@NonNull和IDEA的@Nullable注解如何协同生效
@NonNull由Lombok在编译期注入Objects.requireNonNull检查,只作用于构造函数参数、方法参数和字段赋值;它不改变运行时行为,也不影响泛型擦除后的类型安全。
而@Nullable是给IDE和静态分析工具(如SpotBugs)看的,提示“此处可能为null”,触发警告。两者结合才能形成闭环:Lombok堵住一部分非法空,IDE提醒你检查剩余路径。
- 在Maven中启用
spotbugs-maven-plugin并配置jsr305依赖,才能让@Nullable真正起效 -
@NonNull对getter/setter无效,字段级注解需配合@Data或@Setter才触发生成 - Spring的
@Valid和Hibernate Validator的@NotNull属于运行时校验,与Lombok的编译期检查不冲突,但层级不同
空值安全不是靠某一个API或注解实现的,而是从API设计(返回Optional)、参数契约(文档+注解)、调用习惯(避免裸get())、到构建检查(SpotBugs+CI)的整条链路。最容易被忽略的是:把「空值」当成错误来处理,而不是一种需要建模的业务状态。











