乐趣区

关于java:4-行代码写-3-个NPE异常服了

一、前言

公司刚入职了一名 中级 Java 开发,通过一个星期的适应学习,各方面体现还不错,于是调配了一个小的迭代给新人做。

需要很简略,把从第三方拉取的数据匹配到本身公司后盾设置的渠道后,聚合到一个列表中,批量入库。

然而就在匹配的逻辑中,上线后报了个 NPE,这是作为一名中级开发不应犯的简略谬误,新人被我 狠狠的训了,记生产事变一次。

二、事变重现

伪代码

阐明:伪代码并非实在线上代码,只是为了更不便,更形象的重现事故现场而编写的;实在的业务场景往往更加简单,NPE 的破绽暗藏在更深处,不易 code view 进去,也不易测试进去;生产环境 NPE 是较常见的异样,心愿大家不要纠结为什么测试没测进去,要害还是通过这样一个案例理解 NPE 的起因和解决方案。

// 后盾设置的渠道
String channelNo = channelDao.getOne().getChannelNo();
// 第三方拉取的数据
List<ThirdData> thirdDataList = httpClientUtils.getThirdDatas(DateUtils.today());
// 匹配过滤
thirdDataList.stream().filter(o ->channelNo.equals(o.getChannelNo())).collect(Collectors.toList());
// 批量入库
thirdDataDao.saveAll(thirdDataList);

剖析与解决

有教训、技术扎实的同学看到这里应该或多或少能发现问题了。其实啊,这四段代码是作者精心设计的,堪称是 卧龙凤雏😀😀。

短短 四行代码 竟然凑齐了 3 个 NPE,我枯了 /(ㄒ o ㄒ)/~~

咱们逐行剖析:

第一行剖析

channelDao.getOne()如果返回为 null,那么调用 getChannelNo()会报NPE

解决办法

1、应用防御性编程,提前返回(需依据具体业务场景而定)

// 如果 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("");

第三行剖析(1)

thirdDataList 如果为 null,那么调用 stream()会报NPE

通过上面的源码截图就能晓得起因:

解决办法

1、应用防御性编程,提前返回(举荐)

// 举荐应用汇合工具类判空
if (CollectionUtils.isEmpty(thirdDataList)) {return;}

2、应用 if 条件语句包裹(不举荐)

if (CollectionUtils.isNotEmpty(thirdDataList)) {// 执行前面的逻辑}

第三行剖析(2)

channelNo 如果返回为 null,那么执行 channelNo.equals(o.getChannelNo())会报NPE

咱们晓得,按 Java 的标准 String 的 equals()办法的调用,要求右边是确定值,就是为了防止调用方为 null 的状况。然而这里调用方和 equals 的入参都是变量,这种状况该怎么办呢?

1、再加一句判断:

channelNo != null && channelNo.equals(o.getChannelNo())

2、其实能够用 java.uti 包下的 Objects 类的 equals 办法

Objects.equals(channelNo, o.getChannelNo())

看源码高深莫测,该办法对右边的对象做了非空判断

3、用其余开源的工具类库或者本人实现

如:org.apache.commons.lang3.StringUtils
cn.hutool.core.util.StrUtil;

最初

在这里 l 拉不拉米 要举荐一款 IDEA 的插件:

SonarLint

能动静的帮您查看代码破绽,像 NPE 这种代码危险都会给于相应的提醒。

SonarLint 还有一个赫赫有名的服务端叫SonarQube

退出移动版