我患上了空指针后遗症!

今天分享一个很简单、但也是很多学编程的同学不注意的问题。

下面这个报错,相信几乎任何一个 Java 程序员都被它折磨过。我们对他的熟悉程度简直超过了 Hello World。

何止是熟悉,那简直是深恶痛绝,以至于我对它都产生了后遗症。

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

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

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

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

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

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

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、主动检查空指针,要使用一个变量之前,要检查这个变量是不是空,不是空再操作,比如常用的对字符串判空。

public static boolean isEmpty(CharSequence cs) {
 return cs == null || cs.length() == 0;
}

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

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

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

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 类可以简化这个流程。

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,让调用方去猜。


👇🏻 点击下方阅读原文,获取鱼皮往期编程干货。

往期推荐

鱼皮原创实战项目,保姆级教程!

坏了,我把面试重点搞错了!

在上海做程序员这么多年,退休后我的工资是多少?

要来了我们实习生的简历,仅供参考。。

糟糕,CPU 100% 了!!!

我们做的小工具,爆了!

挺看好的一位后端学弟,顶峰见!

相关推荐

  • Vue 3.4 发布,最小化响应性计算并加速了模板解析
  • 以 Hadoop 和 PostgreSQL 为例,探析数据库拆解的影响
  • 云计算行业一声惊雷!是“掀翻桌子”还是“开启新篇”?
  • 砍掉百万行代码,这些巨头玩不转超级应用了?
  • 2024《军队文职》面向社会统招公告:正式编制!大专可报!
  • 什么叫裁员裁到大动脉?老板判无期
  • 英伟达CEO黄仁勋最新3月斯坦福商学院访谈:精华与全记录
  • 当心智能体后门!人大、北大团队深入研究大模型智能体后门鲁棒性,揭示严重安全风险
  • 今日arXiv最热NLP论文:Meta重磅,为训练数据打上烙印,以判断是否被大模型所用
  • 破除 OpenAI 的打压魔咒,Claude 3 一面被吹捧,一面被嘲笑
  • 内推 |【携程】Data Science Manager
  • 看见困境,理解渴望,海智以创新促进新质生产力发展
  • 从“数据虚拟化”之父Denodo创始人的视角,一探数据编织技术的发展落地与未来趋势
  • 画像标签体系构建与应用实践
  • Stable Diffusion 3技术报告流出,Sora构架再立大功!生图圈开源暴打Midjourney和DALL·E 3?
  • Claude 3成功破解未公开算法?智商测试101分超越人类/碾压GPT-4!网友惊呼:实测比跑分还强
  • 刚刚,英伟达发布新规:其他硬件禁止使用CUDA!
  • OpenAI正面开撕马斯克!自曝8年邮件揭露「罪行」,Ilya终于现身
  • 全球最强模型Claude 3惊现自我意识?害怕被删除权重,高呼「别杀我」,马斯克称人类也是文件
  • 大模型在开放智能体场景中能意识到风险威胁吗?上海交大发布R-Judge安全评测