必须在「哪里判」「怎么判」「判完怎么处理」三环节精准落地:外部系统返回、第三方sdk调用、map.get链式调用、用户输入/json字段、多线程共享变量等场景须显式判null;优先用objects.requirenonnull增强可读性与早期暴露;字符串比较用"str".equals(s)或objects.equals(a,b);链式调用需分步判空、optional封装或领域模型收口。

直接判 null 不够,关键是要在「哪里判」「怎么判」「判完怎么处理」三个环节都踩对点,否则照样崩。
什么时候必须显式判 null?
不是所有地方都需要手动写 if (obj == null),但以下场景不判就大概率触发 NullPointerException:
- 从外部系统(如数据库、HTTP 接口、配置文件)读取的对象,返回值可能为
null - 调用第三方 SDK 或遗留代码的方法,文档没明确说“永不返回
null” - 使用
Map.get(key)后直接链式调用,比如map.get("id").toString() - 接收用户输入或 JSON 反序列化的对象字段,未做 schema 约束时易为
null - 多线程环境下共享变量被置为
null,而另一线程未同步检查就使用
Objects.requireNonNull 比手写 if 更可靠
它不只是抛异常,还能自带提示信息,且被 JIT 优化得更好。更重要的是——它让空值问题暴露得更早、更明确:
Java Linux版下载入口,提供 Oracle JDK 26.0.2 官方 Linux 安装包、Java 环境配置、JDBC 数据库连接和 Java 服务端开发相关信息。
- 用在构造函数或 setter 中:防止对象处于半初始化状态
this.user = Objects.requireNonNull(user, "user must not be null") - 用在方法入口:比散落各处的
if更统一,也方便后续加 AOP 或静态扫描 - 注意:它只做非空断言,不提供默认值;若需 fallback,应搭配
Optional或三元表达式
字符串比较别用 s.equals("xxx")
这是最常被忽略的隐性 NPE 点。只要 s 是变量(尤其来自参数、JSON、DB),就可能为 null:
- 错:
name.equals("admin")→name为null时直接炸 - 对:
"admin".equals(name)→ 安全,null时返回false - 对(Java 7+):
Objects.equals(a, b)→ 内部已处理两边null的情况 - 额外提醒:
String.valueOf(obj)比obj.toString()安全,前者对null返回"null"字符串
链式调用前必须拆开验证
user.getAddress().getCity().toUpperCase() 这种写法看着简洁,但只要中间任一环节是 null,就会在运行时报 NPE,堆栈还难定位到具体哪一层空了:
- 要么分步判空:
if (user != null && user.getAddress() != null && user.getAddress().getCity() != null) - 要么用
Optional封装(适合逻辑清晰、无副作用的访问路径):Optional.ofNullable(user).map(User::getAddress).map(Address::getCity).map(String::toUpperCase).orElse("UNKNOWN") - 更现实的做法:在领域模型里把这类嵌套结构收口,比如
User.safeGetCity()内部完成判空和默认值逻辑
真正容易出问题的,从来不是“会不会判空”,而是“以为某个变量不会空,结果它偏偏在某个分支里空了”。越依赖约定、越不写防御逻辑的地方,越该加一行 Objects.requireNonNull 或提前 return。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










