<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          4 行代碼寫 3 個(gè)NPE異常,服了!

          共 2720字,需瀏覽 6分鐘

           ·

          2022-09-15 18:04

          往期熱門文章:

          1、扔掉工具類!MyBatis 一個(gè)簡(jiǎn)單配置搞定加密、解密,不能太方便了~!
          2、小公司里用SpringBoot做MySQL分庫(kù)分表,踩了一些坑!
          3、沒(méi)有幾十年功力,寫不出這一行“看似無(wú)用”的代碼!!
          4、為什么 Spring和IDEA 都不推薦使用 @Autowired 注解
          5、從阿里跳槽來(lái)的工程師,寫個(gè)Controller都這么優(yōu)雅!

          作者:l拉不拉米 

          來(lái)源:https://juejin.cn/post/7031445206152577061

          一、前言

          公司剛?cè)肼毩艘幻?code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">中級(jí)Java開發(fā),經(jīng)過(guò)一個(gè)星期的適應(yīng)學(xué)習(xí),各方面表現(xiàn)還不錯(cuò),于是分配了一個(gè)小的迭代給新人做。

          需求很簡(jiǎn)單,把從第三方拉取的數(shù)據(jù)匹配到自身公司后臺(tái)設(shè)置的渠道后,聚合到一個(gè)列表中,批量入庫(kù)。

          然而就在匹配的邏輯中,上線后報(bào)了個(gè)NPE,這是作為一名中級(jí)開發(fā)不應(yīng)犯的簡(jiǎn)單錯(cuò)誤,新人被我狠狠的訓(xùn)了,記生產(chǎn)事故一次。

          二、事故重現(xiàn)

          偽代碼

          說(shuō)明:偽代碼并非真實(shí)線上代碼,只是為了更方便,更形象的重現(xiàn)事故現(xiàn)場(chǎng)而編寫的;真實(shí)的業(yè)務(wù)場(chǎng)景往往更加復(fù)雜,NPE的漏洞隱藏在更深處,不易code view出來(lái),也不易測(cè)試出來(lái);生產(chǎn)環(huán)境NPE是較常見的異常,希望大家不要糾結(jié)為什么測(cè)試沒(méi)測(cè)出來(lái),關(guān)鍵還是通過(guò)這樣一個(gè)案例了解NPE的原因和解決方案。

          // 后臺(tái)設(shè)置的渠道
          String channelNo = channelDao.getOne().getChannelNo();
          // 第三方拉取的數(shù)據(jù)
          List<ThirdData> thirdDataList = httpClientUtils.getThirdDatas(DateUtils.today());
          // 匹配過(guò)濾
          thirdDataList.stream().filter(o ->channelNo.equals(o.getChannelNo())).collect(Collectors.toList());
          // 批量入庫(kù)
          thirdDataDao.saveAll(thirdDataList);

          分析與解決

          有經(jīng)驗(yàn)、技術(shù)扎實(shí)的同學(xué)看到這里應(yīng)該或多或少能發(fā)現(xiàn)問(wèn)題了。其實(shí)啊,這四段代碼是作者精心設(shè)計(jì)的,可謂是臥龍鳳雛????。

          短短四行代碼居然湊齊了3個(gè)NPE,我枯了/(ㄒoㄒ)/~~

          我們逐行分析:

          第一行分析

          channelDao.getOne()如果返回為null,那么調(diào)用getChannelNo()會(huì)報(bào)NPE

          解決辦法

          1、使用防御性編程,提前返回(需根據(jù)具體業(yè)務(wù)場(chǎng)景而定)

          // 如果channelNo是方法邏輯執(zhí)行的必須元素,推薦用此方法
          Channel channel = channelDao.getOne();
          if (channel == null) {
              return;
          }

          2、使用三目運(yùn)算,返回空字符串("")

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

          3、使用Optional函數(shù),返回空字符串("")

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

          第三行分析(1)

          thirdDataList如果為null,那么調(diào)用stream()會(huì)報(bào)NPE。

          通過(guò)下面的源碼截圖就能知道原因:

          image.png
          image.png

          解決辦法

          1、使用防御性編程,提前返回(推薦)

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

          2、使用if條件語(yǔ)句包裹(不推薦)

          if (CollectionUtils.isNotEmpty(thirdDataList)) {
              // 執(zhí)行后面的邏輯
          }

          第三行分析(2)

          channelNo如果返回為null,那么執(zhí)行channelNo.equals(o.getChannelNo())會(huì)報(bào)NPE。

          我們知道,按Java的規(guī)范String的equals()方法的調(diào)用,要求左邊是確定值,就是為了避免調(diào)用方為null的情況。然而這里調(diào)用方和equals的入?yún)⒍际亲兞浚@種情況該怎么辦呢?

          1、再加一句判斷:

          channelNo != null && channelNo.equals(o.getChannelNo())
          復(fù)制代碼

          2、其實(shí)可以用java.uti包下的Objects類的equals方法

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

          看源碼一目了然,該方法對(duì)左邊的對(duì)象做了非空判斷

          image.png

          3、用其他開源的工具類庫(kù)或者自己實(shí)現(xiàn)

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

          最后

          在這里l拉不拉米要推薦一款I(lǐng)DEA的插件:

          SonarLint

          image.png

          能動(dòng)態(tài)的幫您檢查代碼漏洞,像NPE這種代碼風(fēng)險(xiǎn)都會(huì)給于相應(yīng)的提示。

          SonarLint還有一個(gè)大名鼎鼎的服務(wù)端叫SonarQube。

          往期熱門文章:

          1、國(guó)產(chǎn)開發(fā)工具的天花板,用來(lái)擼項(xiàng)目真香!
          2、這個(gè) MySQL bug 99% 的人會(huì)踩坑!
          3、公司產(chǎn)品太多了,怎么實(shí)現(xiàn)一次登錄產(chǎn)品互通?
          4、Redis 官方可視化工具,高顏值,功能太強(qiáng)大!
          5、用了BigDecimal就不會(huì)資損?了解下BigDecimal這五個(gè)坑
          6、一個(gè)依賴搞定 Spring Boot 反爬蟲,防止接口盜刷!
          7、千萬(wàn)不要把 Request 傳遞到異步線程里面!有坑!
          8、不卷了!入職字節(jié)一周就果斷跑了。
          9、SpringBoot+ShardingSphereJDBC實(shí)現(xiàn)讀寫分離!
          10、不好意思, Maven 該換了!

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人a一级毛片免费看 | 国内精品在线观看小视频 | 中文字幕无码一区二区三区一本久 | www操逼| 色综合区|