公司新入职一个 Java 中级开发,4 行代码写出了 3 个异常,我真的服...

共 3640字,需浏览 8分钟

 ·

2022-10-15 03:20

点击关注公众号,Java干货 及时送达 c78d40a35af551e310a34d7935373646.webp

作者:l拉不拉米
链接:https://juejin.cn/post/7031445206152577061

一、前言

Hello 大家好,我是l拉不拉米,今天带来一个真实案例,让大家更深刻的理解空指针异常

公司刚入职了一名中级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ㄒ)/~~

推荐一个开源免费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

我们逐行分析:

第一行分析

channelDao.getOne()如果返回为null,那么调用getChannelNo()会报NPE。另外,最新 Java 面试题整理好了,大家可以在Java面试库小程序在线刷题。

解决办法

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避免空指针的 5 个案例!建议你看下。

通过下面的源码截图就能知道原因:

7874ac507f3a6f46de75a381772f0bdf.webp8dd555883ca5328e0eeba403c067cf63.webp

解决办法

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())

看源码一目了然,该方法对左边的对象做了非空判断

2445ed1ffec34fc3abc76bf40bb134fd.webp

3、用其他开源的工具类库或者自己实现

如:

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

最后

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

SonarLint

dfeffeb037c1e630c1ed66dce1615622.webp

能动态的帮您检查代码漏洞,像NPE这种代码风险都会给于相应的提示。

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

End


Spring Boot 学习笔记,这个太全了!

23 种设计模式实战(很全)

Nacos 2.1.1 正式发布,真心强!

Spring Cloud Alibaba 最新重磅发布!

Stream 中的 map、peek、foreach 方法的区别?

fde0adad4a656b7904c775a59812a0a2.webpSpring Cloud 微服务最新课程!
浏览 25
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报