在 Java 中使用对象属性时,并非需要无脑加大量 if 判空,但也不能完全忽略空值校验 —— 核心是根据场景判断是否需要判空、以及如何优雅地判空,避免冗余代码和空指针异常(NPE)。下面从「为什么需要判空」「什么时候需要判空」「如何优雅判空(替代大量 if)」三个维度详细说明:



三、如何优雅判空(替代大量 if)?
推荐用更简洁的方式替代嵌套 / 冗余的 if 判空,既保证安全,又提升代码可读性
用Optional来实现
1. 使用 Java 8+ Optional(推荐)
Optional 是 Java 8 引入的「空值容器」,专门解决 NPE 问题,替代嵌套 if 判空:
// 优雅获取用户地址的城市(避免嵌套if)
String city = Optional.ofNullable(order)
.map(Order::getUser) // 若order非null,取user;否则返回空Optional
.map(User::getAddress) // 若user非null,取address;否则返回空Optional
.map(Address::getCity) // 若address非null,取city;否则返回空Optional
.orElse("默认城市"); // 所有步骤都空时,返回默认值
// 也可直接判断是否存在值
if (Optional.ofNullable(user).isPresent()) {
// 处理非空逻辑
}
// 直接消费非空值(更简洁)
Optional.ofNullable(user).ifPresent(u -> {
System.out.println(u.getName());
});
2. 使用工具类(Apache Commons / Spring)
第三方工具类封装了判空逻辑,简化单属性判空:
// Apache Commons Lang3
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
// 对象判空,返回默认值
User user = ObjectUtils.defaultIfNull(inputUser, new User());
// 字符串判空(空字符串/空格也视为空)
String name = StringUtils.defaultIfBlank(user.getName(), "未知");
// Spring Core(无需额外依赖)
import org.springframework.util.ObjectUtils;
if (!ObjectUtils.isEmpty(user)) { // 同时判断null和空集合/空字符串
// 处理逻辑
}
3. 提前返回(扁平化判空)
替代嵌套 if,通过「提前返回」让代码更清晰
public String getCity(Order order) {
if (order == null) {
return "默认城市";
}
User user = order.getUser();
if (user == null) {
return "默认城市";
}
Address address = user.getAddress();
if (address == null) {
return "默认城市";
}
return address.getCity();
}
4. 避免不必要的判空(减少 if)
- 初始化时保证非空:比如集合默认初始化为
new ArrayList<>(),而非 null; - 使用空对象模式:定义一个「空实现类」替代 null,比如
EmptyUser extends User,避免判空; - 通过注解约束:比如接口入参用
@NotNull(JSR 303),由框架提前校验,无需手动判空; - 数据库层面约束:非空字段加 NOT NULL,减少查询结果为 null 的情况。
四、总结
- 不要无脑加 if 判空:只对「外部输入、不可控数据」判空,可控场景(如自己创建的对象)无需判空;
- 拒绝嵌套 if:用 Optional、工具类、提前返回替代,提升代码可读性;
- 从源头减少 null:通过初始化、注解、数据库约束等方式,减少需要判空的场景。
最终目标是:既避免 NPE,又不让代码被大量 if 判空淹没 —— 让判空逻辑「隐形」或「简洁」,聚焦业务逻辑本身。
最后补充
“不可控的输入” 本质是来源不受当前代码掌控、无法保证非空 的数据
一、外部系统 / 服务交互类(跨边界数据)





二、框架 / 容器注入 / 上下文类(依赖外部初始化)
这类数据由框架 / 容器管理,初始化时机或存在性不可控,需判空:




三、集合 / 数组 / 复杂数据结构类(元素不可控)
集合 / 数组本身可能非 null,但内部元素 不可控,需判空:



四、其他易忽略的不可控场景



核心判空原则(补充)
对以上不可控输入,判空时需注意:
- 分层判空:跨边界的第一层数据(如 RPC 返回值、HTTP 参数)必须判空;嵌套属性可通过
Optional简化(如Optional.ofNullable(order).map(Order::getUser)...); - 区别 “空值” 和 “空集合 / 空字符串”:用
StringUtils.isBlank()(处理空字符串 / 空格)、CollectionUtils.isEmpty()(处理空集合)替代单纯的== null; - 兜底策略:判空后需有明确的兜底逻辑(返回默认值、抛业务异常、记录日志),而非仅
if (xxx != null)无后续处理。
总结:只要数据的「产生、传递、存储」环节不受当前代码完全掌控,就属于 “不可控输入”,使用前必须判空 —— 核心是 “谁产生谁不保证非空,谁使用谁判空”。

356

被折叠的 条评论
为什么被折叠?



