为什么牛逼的程序员都不用 “ ! = null " 做判空?
yuyutoo 2025-07-06 17:44 5 浏览 0 评论
有没有发现一个很奇怪的现象?很多资深程序员写 Java 代码时,几乎很少出现那种我们耳熟能详的判空写法:
if (obj != null) {
obj.doSomething();
}
反而是我们这些刚入门或者中级选手,代码里全是这种“if 不等于 null 就继续”的写法,看起来特别勤奋谨慎,实际上反而显得代码零碎又啰嗦。
这不是你一个人的问题,这是 Java 项目里普遍存在的“判空焦虑症”。
那为啥那些老江湖写代码可以这么潇洒?难道他们心态更强大,不怕空指针报错?当然不是。真相是:他们从设计上就避免了大量判空的场景。而我们呢?啥都不确定,搞得每行代码都像走钢丝,一步不小心就 null。
今天就来聊聊:为啥牛逼的程序员都不怎么写 != null,以及我们应该怎么改。
空指针到底该怎么对待?
Java 的空指针异常(NullPointerException),简直是写 Java 的人挥之不去的梦魇。大部分程序员为了避免 NPE,把代码写得像武侠小说一样,“步步为营、处处设防”,好不容易走到终点,却发现性能也拉了、可读性也糊了,关键 NPE 还没躲掉!
但真高手不是这么写代码的。
我们要先搞清楚一个前提:你的程序到底允不允许返回 null?
这个问题看起来简单,其实是区分新手和老手的关键。
如果你设计的方法是 API 层的一部分,某个参数或者返回值对逻辑执行来说是必须存在的,那你就别返回 null,直接抛异常!没错,你没听错,不要偷偷摸摸返回个 null 等着别人来猜你想干嘛,而是应该光明正大地告诉调用方:“兄弟,你这参数不合格,赶紧改。”
比如你写了一个获取用户信息的方法:
public User getUserById(String id) {
if (id == null) return null; // 新手代码
// 查询数据库逻辑
}
这种代码看起来“温柔体贴”,实际上就像是你去饭店点了一份牛排,结果厨子默默地没做还给你上了个空盘子。高手会直接这么干:
public User getUserById(String id) {
if (id == null) {
throw new IllegalArgumentException("id 不能为空");
}
// 查询数据库逻辑
}
出问题就报错,别憋着。
真的要返回 null 的情况,怎么写才优雅?
有时候,确实是业务允许返回 null,比如你查一个商品库存,发现确实没货,那返回 null 好像也说得过去。
但这里也有个更优雅的写法:空对象模式(Null Object Pattern)。
简单讲,就是你不要真的返回 null,你可以返回一个“空对象”,它啥都不干,但它确实是个对象,这样你就能安全地调用它的方法了。
举个栗子:
public interface Action {
void doSomething();
}
你写了个解析器 Parser,它根据输入返回一个动作 Action:
public Action findAction(String userInput) {
if ("print".equals(userInput)) {
return new PrintAction();
}
return null; // 这是个坑
}
然后你调用:
Action action = parser.findAction(input);
if (action != null) {
action.doSomething();
}
这个判断是不是眼熟?问题是你每次调用都得加这句,烦不烦?
换成空对象模式试试看:
public class NullAction implements Action {
public void doSomething() {
// 啥也不干
}
}
publicclass MyParser implements Parser {
privatestaticfinal Action DO_NOTHING = new NullAction();
public Action findAction(String userInput) {
if ("print".equals(userInput)) {
returnnew PrintAction();
}
return DO_NOTHING;
}
}
再调用时就可以爽快地写:
parser.findAction(input).doSomething();
这就是高手的写法,思路清晰,不怕空,根本不需要判断。
返回集合类型时,千万别返回 null!
这个坑真的是每个 Java 人都踩过一脚。
比如:
public List<String> getUserRoles(String userId) {
if (userId == null) return null;
// 查数据库,如果没有权限,返回 null?
}
你这样写,调用的时候就得小心翼翼:
List<String> roles = getUserRoles(userId);
if (roles != null && !roles.isEmpty()) {
// 有权限逻辑
}
老程序员直接写:
return Collections.emptyList();
然后调用侧就可以放飞自我了:
for (String role : getUserRoles(userId)) {
// 啥也不用判断,开开心心地遍历
}
就问一句:你愿意每次都写一堆判空代码,还是愿意一次性在返回值上处理好问题?
Java 8 的 Optional 怎么看?
这是个挺有争议的东西。
Optional<T> 本质上是个容器,用来优雅地表达“可能有值、可能没值”的语义。
比如:
public Optional<User> findUser(String id) {
return Optional.ofNullable(userRepository.get(id));
}
调用的时候:
findUser(id).ifPresent(user -> user.sayHi());
或者:
User user = findUser(id).orElse(new User("默认用户"));
看起来是不是挺高级?但我跟很多人一样,觉得 Optional 在业务逻辑里用得多了,反而容易让人绕晕,尤其是层层 Optional 嵌套的时候,代码会变得很“奇技淫巧”。
所以我个人建议:**Optional 可以用,但别滥用。**用在一些辅助方法或框架内部还行,核心业务逻辑中,不如直接用空对象或抛异常。
判空的时候,也有技巧
比如说,我们写字符串判断:
if (foo != null && foo.equals("bar")) {
// do something
}
一看就知道是怕 foo 是 null。那高手怎么写?
if ("bar".equals(foo)) {
// 安全又简洁
}
因为 "bar" 是常量,不可能是 null,就能放心大胆地调用它的 equals 方法。这种写法也是我们在项目里常用的“对调 equals”技巧。
写在最后
老程序员不写 != null,不是他们不怕出事,而是他们从根上解决了这些事。
他们通过:
- 提前抛出异常防止脏数据传进来
- 空对象模式让返回值永远不是 null
- 集合类型直接返回 empty list
- 使用 Optional 表达可能缺省的值
- 代码风格上习惯用常量调用 equals
从设计到实现,压根不给 NPE 留下“生根发芽”的机会。你还在满项目地写 if (xxx != null),他们已经在另一种语言模式下自由驰骋了。
所以,写 Java 的我们,其实可以更优雅一点。
空指针报错不怕,怕的是你为了“避免出错”,把代码写得又臭又长。
程序员的成长,从敢于抛异常开始。
相关推荐
- 全局和隐式 using 指令详解(全局命令)
-
1.什么是全局和隐式using?在.NET6及更高版本中,Microsoft引入了...
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
-
1、介绍模块化单体是一种架构风格,代码是根据模块的概念构成的。对于许多组织而言,模块化单体可能是一个很好的选择。它有助于保持一定程度的独立性,这有助于我们在需要的时候轻松过渡到微服务架构。Spri...
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
-
我是一位多年后端经验的工程师,其中前几年用ASP.NET...
- .NET AOT 详解(.net 6 aot)
-
简介AOT(Ahead-Of-TimeCompilation)是一种将代码直接编译为机器码的技术,与传统的...
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
-
哈喽,我是老鱼,一名致力于在技术道路上的终身学习者、实践者、分享者!...
- asar归档解包(游戏arc文件解包)
-
要学习Electron逆向,首先要有一个Electron开发的程序的发布的包,这里就以其官方的electron-quick-start作为例子来进行一下逆向的过程。...
- 在PyCharm 中免费集成Amazon CodeWhisperer
-
CodeWhisperer是Amazon发布的一款免费的AI编程辅助小工具,可在你的集成开发环境(IDE)中生成实时单行或全函数代码建议,帮助你快速构建软件。简单来说,AmazonCodeWhi...
- 2014年最优秀JavaScript编辑器大盘点
-
1.WebstormWebStorm是一种轻量级的、功能强大的IDE,为Node.js复杂的客户端开发和服务器端开发提供完美的解决方案。WebStorm的智能代码编辑器支持JavaScript,...
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
-
项目简介:基于JS的超轻量级聊天软件。前端:vue、iview、electron实现的PC桌面版聊天程序,主要适用于私有云项目内部聊天,企业内部管理通讯等功能,主要通讯协议websocket。支持...
- JetBrains Toolbox推出全新产品订阅授权模式
-
捷克知名软件开发公司JetBrains最为人所熟知的产品是Java编程语言开发撰写时所用的集成开发环境IntelliJIDEA,相信很多开发者都有所了解。而近期自2015年11月2日起,JetBr...
- idea最新激活jetbrains-agent.jar包,亲测有效
-
这里分享一个2019.3.3版本的jetbrains-agent.jar,亲测有效,在网上找了很多都不能使用,终于找到一个可以使用的了,这里分享一下具体激活步骤,此方法适用于Jebrains家所有产品...
- CountDownTimer的理解(countdowntomars)
-
CountDownTimer是android开发常用的计时类,按照注释中的说明使用方法如下:kotlin:object:CountDownTimer(30000,1000){...
- 反射为什么性能会很慢?(反射时为什么会越来越长)
-
1.背景前段时间维护一个5、6年前的项目,项目总是在某些功能使用上不尽人意,性能上总是差一些,仔细过了一下代码发现使用了不少封装好的工具类,工具类里面用了好多的反射,反射会影响到执行效率吗?盲猜了一...
- btrace 开源!基于 Systrace 高性能 Trace 工具
-
介绍btrace(又名RheaTrace)是抖音基础技术团队自研的一款高性能AndroidTrace工具,它基于Systrace实现,并针对Systrace不足之处加以改进,核心改进...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- .NET 奇葩问题调试经历之3——使用了grpc通讯类库后,内存一直增长......
- 全局和隐式 using 指令详解(全局命令)
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
- .NET AOT 详解(.net 6 aot)
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
- asar归档解包(游戏arc文件解包)
- 在PyCharm 中免费集成Amazon CodeWhisperer
- 2014年最优秀JavaScript编辑器大盘点
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)