中级 Java 开发匹配逻辑中出现空指针异常,新人被训记生产事故

2024-06-13
来源:网络整理

点击上方的“宇道源代码”,选择“”

谁关心第一波或第二波?

能掀起的浪花才是好浪花!

每天10点33分更新文章,每天都会掉一点头发……

源代码精品专栏

大家好,今天我给大家带来一个真实的案例,帮助大家更深入的理解空指针异常。

公司刚招了一位中级Java开发人员,经过一周的适应和学习,他各方面表现都还不错,所以就给新人安排了一个小迭代的工作。

需求很简单,把第三方拉来的数据和公司后台设置的渠道匹配之后,汇总成一个列表,然后分批存储。

但是在匹配逻辑上,上线后报了NPE,这是一个中级开发人员不应该犯的简单错误,我狠狠地训斥了新人一顿,并记录为生产事故。

基于Boot+Plus+Vue&的后端管理系统+用户小程序,支持RBAC动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

注意:伪代码并非真实的线上代码,只是为了更方便形象的复现事故现场而写的。真实的业务场景往往更加复杂,NPE漏洞隐藏的更深,难以查看和测试。NPE是生产环境中常见的异常,希望大家不要纠结为什么没测试出来,关键还是要通过这样的案例,了解NPE的成因和解决办法。

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

有经验、功底扎实的同学看到这里应该或多或少能发现问题所在,其实这四段代码都是作者精心设计的,可谓是龙凤呈祥。

短短四行代码就有3个NPE,累死我了/(ㄒoㄒ)/~~

我们来逐行分析一下:

如果 .() 返回 null,则调用 () 将导致 NPE。

// 如果channelNo是方法逻辑执行的必须元素,推荐用此方法
Channel channel = channelDao.getOne();
if (channel == null) {
    return;
}

// 返回兜底的空字符串
String channelNo = channelDao.getOne() == null ? "" : channelDao.getOne().getChannelNo();

String channelNo = Optional.ofNullable(channelDao.getOne()).orElse("");

如果为空,调用()会报NPE。

以下源代码截图显示了原因:

// 推荐使用集合工具类判空
if (CollectionUtils.isEmpty(thirdDataList)) {
    return;
}

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

如果返回值为空,执行.(o.())将导致NPE。

我们知道,按照 Java 规范,() 方法调用时,要求左边有一个确定的值,以避免出现 为 null 的情况。但这里 和输入参数都是变量,这种情况该怎么办呢?

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

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

从源码中可以清楚的看出,这个方法对左边的对象做了一个非空的判断。

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


基于++Vue&++用户小程序的后端管理系统,支持RBAC动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

这里给大家推荐一个IDEA插件:

能够帮助您动态检查代码漏洞,并对NPE等代码风险给出相应提示。

还有一个著名的服务器叫做。

欢迎加入我的知识星球,一起讨论架构、交流源码,加入请长按下方二维码:

源代码分析在知识星球更新如下:

近期更新的《云道2.X入门》系列文章超过101篇文章,涵盖了ES、分片、读写分离、权限、性能测试等内容。

提供近3万行代码的示例以及超4万行代码的电商微服务项目。

分享