我患上了空指针后遗症

🍄 大家好,我是风筝

🌍 个人博客:【古时的风筝】。

本文目的为个人学习记录及知识分享。如果有什么不正确、不严谨的地方请及时指正,不胜感激。

每一个赞都是我前进的动力。

公众号:「古时的风筝」

下面这个报错,相信没有任何一个 Java 程序员没有被它折磨过。我们对他的熟悉程度简直超过了 Hello World。 何止是熟悉,那简直是深恶痛绝,以至于我对它都产生了后遗症。

每当本地调试出现这个错误的时候,都恨不得掐一下大腿,然后默默的对自己说:垃圾,还犯这么愚蠢的错误呢?

不知道有多少同学和我一样有这种感受呢?

回想起我之前接手的一个项目,线上出现了问题,当我到了服务器一看日志,只有几个单词,那就是 java.lang.NullPointerException,那一刻我是头晕目眩,差点一头撞在 27 寸的显示器上。回想上一次出现这种症状,还是几年前挤早高峰的公交车,挤的我双脚离地,外加有点低血糖。

当然主要问题并不是 NLP(NullPointerException),还是要仰仗前辈异常处理的"非常优秀",异常包裹的严严实实的,只留了java.lang.NullPointerException这一点点信息。

于是只能打开代码,找到报错的接口,一步步排查,满眼看去,皆可空指针啊。从此之后,空指针异常给我留下了深深的阴影。

好在从 JDK 14之后,NLP 异常不再仅仅是简单的这几个单词了,而会附带更加具体的异常信息,比如对一个赋值为 null 的字符串求长度,能捕捉到下面这样的异常信息:

csharp 复制代码
Cannot invoke "String.length()" because "s" is null

空指针的由来

要说空指针异常,那还不只是 Java 的问题,绝大多数语言都有这个问题,比如 C++、C#、Go,但是也有没有这个问题,比如 Rust 。

空指针最早是编程界的鼻祖级人物 Tony Hoare 引入的,早在 1965年,他设计 ALGOL 60 语言的时候引入了Null 的设计,ALGOL 可谓是 C 语言的祖宗。ALGOL 中的 Null 被后来的众多语言设计者引入,就包括前面提到的这些语言。

Tony Hoare 不仅发明了我们熟悉的 Null,还是令众多算法残废闻风丧胆的快速排序算法(Quick Sort)的发明者,这个算法也是当前世界上使用最广泛的算法之一。

2009年3月他在Qcon技术会议上发表了题为「Null引用:代价十亿美元的错误」的演讲,回忆自己1965年设计第一个全面的类型系统时,未能抵御住诱惑,加入了Null引用,仅仅是因为实现起来非常容易。它后来成为许多程序设计语言的标准特性,导致了数不清的错误、漏洞和系统崩溃,可能在之后40年中造成了十亿美元的损失

如何应对空指针

处理空指针有一些措施,我们常常称之为「防御式编程」,这个说法也很形象,你不防着它,它真的就上来伤害你。

**1、**主动检查空指针,要使用一个变量之前,要检查这个变量是不是空,不是空再操作,比如常用的对字符串判空。

java 复制代码
public static boolean isEmpty(CharSequence cs) {
	return cs == null || cs.length() == 0;
}

对应的很多字符串工具类都有 isEmptyisNotEmptyisNotBlank 这种方法。

同样的,还有对于集合的判断,好多工具包都有 CollectionUtil.isEmpty这样的方法。

为了避免空引用异常,有时候我们写的代码可能想下面这个样子,一步一判空。这样可以提高代码的健壮性和可靠性,但是看上去并不是很美观。

java 复制代码
public static String getUserOrderDetail(Integer userId) {
	User user = User.getUser(userId);
	if (user != null) {
		Order order = user.getOrder();
		if (order != null) {
			Address address = order.getAddress();
			if (address != null) {
				String detail = address.getDetail();
				if (detail != null) {
					return detail;
				}
			}
		}
	}
	return "不好意思,找了半天,没找到";
}

还好,Java 8 中引入的 Optional 类可以简化这个流程。

java 复制代码
public static String getUserOrderDetail(Integer userId) {
	return Optional.ofNullable(User.getUser(userId))
			.map(User::getOrder)
			.map(Order::getAddress)
			.map(Address::getDetail)
			.orElse("不好意思,找了半天,没找到");
}

2、 能不返回 NULL 的话,就尽量不返回 NULL

比如有些获取集合的方法,没有结果的话,可以返回一个空列表。这种方式对于提供给前端或者消费者使用的接口更加适用,返回一个空集合要远比返回一个空更友好。

3、 能抛异常的话,宁可抛异常,也不要返回 NULL

还有一些情况,抛出给调用者一个具体的异常,要比返回一个 NULL 更加能让调用者清楚到底发生了什么。

比如根据一个用户的信息,但是发现用户不存在了,直接返回给调用者一个「用户不存在」的异常信息更明确,而不是返回一个 NULL,让调用方去猜。

RPC框架的核心到底是什么

相关推荐
90后的晨仔2 分钟前
Python 进阶:海象运算符与模式匹配,让你的代码更优雅!
后端
卷无止境6 小时前
智能体开发环境ADE浅析,编程工具的下一次范式跃迁
后端·python
码事漫谈9 小时前
DeepSeek 这波操作很凶
后端
CharlesYu0110 小时前
前端性能优化的第一性原理,是不断缩短“用户发起意图 → 获得可用结果”之间的时间
前端
Bs_MoneyMagnet10 小时前
基于springboot+vue的医疗健康便民服务平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
平头哥技术团队10 小时前
Day 21 _ 页内锚点_给每段起个 id,目录写 href=_#id_,点一下页面就滚到那一段
前端·html·html5
子兮曰11 小时前
Bun v1.4.1 深度解析:从 Zig 到 Rust,一场 11 天、64 个 AI 代理的语言迁徙
前端·后端·bun
人民广场吃泡面12 小时前
什么是AI Agent?它又能给前端带来哪些效率提升?
前端·人工智能
中科三方12 小时前
两家域名注册商资质被ICANN终止:企业域名资产安全再受关注
前端·网络·安全·域名
bug总结12 小时前
uniapp vue3全局方法注册使用
前端·javascript·uni-app