Java开发中避免空指针异常的真实案例分析与教训总结
大家好,我是Java架构师

一、前言
大家好,我是 l 拉不拉米。今天给大家带来一个真实案例,以便让大家能更深刻地理解空指针异常。
公司新入职了一位中级 Java 开发人员。经过一周的适应与学习后,其在各方面的表现都较为良好。因此,为这位新人分配了一个较小的迭代任务让其去做。
需求较为简单,需将从第三方拉取的数据与自身公司后台所设置的渠道进行匹配,接着把匹配后的数据聚合到一个列表里,最后将其批量入库。
然而在匹配的逻辑方面,上线之后出现了一个 NPE 。这是一名中级开发不应该犯的较为简单的错误,我狠狠地训斥了那个新人,并且记录了一次生产事故。
二、事故重现伪代码
伪代码并非真实线上代码,只是为方便、形象地重现事故现场而编写;真实业务场景更复杂,NPE 漏洞隐藏较深,不易通过 code view 看出,也不易测试出来;生产环境中 NPE 是较常见的异常,希望大家不要纠结为何测试未测出,关键是通过此案例了解 NPE 的原因和解决方案。
// 后台设置的渠道
获取到的一个对象,通过 channelDao.getOne() 获取到,该对象的 channelNo 属性被赋值给了 String 类型的变量 channelNo 。
// 第三方拉取的数据
ListthirdDataList 等于 httpClientUtils 获取的今日的第三方数据,即 httpClientUtils.getThirdDatas(DateUtils.today());
// 匹配过滤
从 thirdDataList 中筛选出满足条件的元素,条件是元素的 channelNo 与指定的 channelNo 相等,然后将筛选后的元素收集为一个列表。
// 批量入库
thirdDataDao 对 thirdDataList 进行保存操作,即将 thirdDataList 中的所有数据保存起来。
分析与解决
有经验且技术扎实的同学看到此处,应该能发现一些问题。实际上,这四段代码是作者精心构思的,它们可以说是各有特点,就像卧龙和凤雏一样。
短短四行代码居然凑齐了3个NPE,我枯了/(ㄒoㄒ)/~~
推荐一个开源免费的 Spring Boot 最全教程:
我们逐行分析:
第一行分析
如果 channelDao.getOne()返回为 null,那么调用 getChannelNo()就会报 NPE。
解决办法:其一,运用防御性编程,提前进行返回操作,不过这需依据具体的业务场景来确定。
// 如果channelNo是方法逻辑执行的必须元素,推荐用此方法
Channel channel = channelDao.getOne();
if (channel == null) {
return;
}
2、使用三目运算,返回空字符串("")
// 返回兜底的空字符串
String channelNo = channelDao.getOne() == null ? "" : channelDao.getOne().getChannelNo();
3、使用Optional函数,返回空字符串("")
String channelNo = Optional.ofNullable(channelDao.getOne()).orElse("");
l,那么调用stream()会报NPE。建议你看下。
通过下面的源码截图就能知道原因:
解决办法1、使用防御性编程,提前返回(推荐)
// 推荐使用集合工具类判空
if如果 thirdDataList 为空(即 CollectionUtils.isEmpty(thirdDataList) 为 true),那么 {
return;
}
2、使用if条件语句包裹(不推荐)
if若 thirdDataList 不是空的,就会:
// 执行后面的逻辑
}
第三行分析(2)
如果 channelNo 返回为 null,那么执行 channelNo.equals(o.getChannelNo())就会报 NPE。
我们知晓,依据 Java 的规范,对于 String 的 equals()方法的调用,需要左边是确定的值,这样做的目的是避免调用方为 null 的情况。然而在此处,调用方以及 equals 的入参均为变量,面对这种情况应当如何处理呢?另外,倘若搜索公众号顶级算法的后台并回复“算法心得”,便可以获取一份令人惊喜的礼包。
1、再加一句判断:
channelNo != nullchannelNo 与 o.getChannelNo()相等
其实可以使用 java.uti 包中的 Objects 类的 equals 方法。
Objects 对 channelNo 和 o.getChannelNo()进行比较,判断它们是否相等。
看源码一目了然,该方法对左边的对象做了非空判断
3、用其他开源的工具类库或者自己实现
如:
Apache 旗下的 commons-lang3 库中的 StringUtils 类。
cn.hutool.core.util.StrUtil;
最后
在这里l拉不拉米要推荐一款IDEA的插件:
SonarLint
可以动态地为您检查代码漏洞,对于像 NPE 这样的代码风险,都会给予相应的提示。
SonarLint 拥有一个较为知名的服务端,这个服务端被称作 SonarQube。
欢迎有需求的同学进行尝试。如果本文对您有帮助,那么也请您帮忙点个赞并且点个在看。
在 GitHub猿 还有更多优质项目系统学习资源,欢迎分享给其他同学吧!
最后整理了 400 多套项目,并且将这些项目赠送给了读者。如果想要获取这些项目,只需扫描下方二维码,然后在后台回复【赚钱】即可。