说个特别常见但又特别容易被忽视的小习惯:**到处写if(x != null)**。 很多人写代码时完全是条件反射,脑子还没反应,手已经敲上去了。
这事我以前也一样,写接口、写工具类、写 DTO 组装,基本所有逻辑的第一行都是判空。写得久了你会发现代码越来越臃肿,看起来到处都是安全网,但其实有些网根本没必要自己织。
结果就是——代码越来越啰嗦,却不一定更安全。
然后某天我在一个项目里把这个坏习惯改掉了,一秒钟的事,代码瞬间“瘦身”。
如果我们一直在写!= null会怎样?
举个真实的业务代码例子(我保证你一定见过类似写法):
if (user != null) {
if (user.getAddress() != null) {
if (user.getAddress().getCity() != null) {
return user.getAddress().getCity().getName();
}
}
}
return "";
这段代码看似很安全,但实际上:
可读性极差
层层嵌套让逻辑变得沉重
扩展性差
填补不了真正的业务漏洞
而且还有个经典问题:你并不能因为加了十个判空,就认为系统安全了。
因为大多数 null,本质上是数据设计问题而不是代码写法问题。
一秒钟替换掉:用Optional
Java 8 给我们准备的Optional,就是帮你“戒掉判空”的神器。
同样逻辑换成这样:
String cityName = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(City::getName)
.orElse("");
一秒钟理解:从外到内一步步取值,中途有 null 就自动停止,不抛异常,也不需要你写一堆 if。
而且代码逻辑结构天然清晰。
Optional 不是“酷炫”,是真有用
看起来只是“减少几行代码”,但它带来的收益其实是体系级的:
让逻辑变线性,不嵌套
判空本质就是嵌套,嵌套一多,可读性立刻下降。
Optional 的 map 结构让你像写 SQL 一样“流式处理”。
你可以把 Optional 返回给调用方
以前你可能写:
public City getCity(User user) {
if (user == null || user.getAddress() == null) {
return null;
}
return user.getAddress().getCity();
}
现在你可以写:
public Optional<City> getCity(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity);
}
调用方也不用判空了:
String name = getCity(user)
.map(City::getName)
.orElse("未知城市");
这就是一种设计层面的优化。
那 Optional 有不能用的地方吗?
有两点你一定要注意:
不要用 Optional 修饰字段
也就是这种写法:
public class User {
private Optional<Address> address;
}
这会极大增加序列化复杂度,通常也是违背设计初衷的。
不要在性能关键区使用 Optional(极端情况)
比如百万级循环内纯 CPU 操作。 大部分业务场景可以无脑用,别想太多。
那我到底什么时候应该“不写 != null”?
其实很好判断:你只要问自己一个问题:
“这个 null 是业务可控的吗?”
比如:
入参与数据库读出来的数据 可控
外部系统调用返回的对象 不可控
第三方 SDK / 解析 JSON 不可控
新增字段还没全量初始化 不可控
可控的就用 Optional 优雅处理,不可控的你再判空也不迟。
如果你现在的项目里还有大量!= null,怎么改?
也别一下全改,风险太大。最合理的方式是:
从 DTO 转换开始改(最容易见效)
公共工具方法开始改(收益最高)
新业务默认拒绝重复写!= null
Review 里加一条“能 Optional 就不用判空”
你会看到代码结构在变清晰。
当你第一次写出这行代码的时候:
Optional.ofNullable(xxx)
你会突然意识到:
原来我过去那些判空,真的没有必要。
这是一个成本近乎为零,却能提升代码质量的习惯改善。