1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        7 個 JDK 中的坑

        共 5106字,需瀏覽 11分鐘

         ·

        2021-04-23 15:13

        「今日推薦」


        新版 IDEA 2021.1正式發(fā)布,新增了這幾個超實用功能!
        推薦3個快速開發(fā)平臺 前后端都有 項目經驗又有著落了
        拜托!不要用“ ! = null " 做判空了

        JDK 作為我們每天必備的調用類庫,里面大量提供了基礎類供我們使用.可以說離開JDK,我們的 Java 代碼寸步難行, JDK 帶給我們的便利可謂是不勝枚舉,但同時這些方法在使用起來也存在一些坑,如果不注意就很容易掉入到陷阱里面,導致程序拋出錯誤。
        JDK 中的很多方法都不會做非 null 判斷,可能設計 JDK 的作者默認開發(fā)者已經處理好null值了.不過這個設計可能會造成很嚴重的后果,實在是暗藏殺機。
        比如今天早上我們查了一筆訂單沒有退款,查了一早上最終才發(fā)現(xiàn)是同事寫的代碼的BigDecimal 的 subtract 方法的值沒有做非 null 判斷處理導致程序拋出了空指針異常,看似簡單的異常卻直接無法讓很多訂單退款,是在是小問題造成大事故。
        而要修補退款這個問題,要耗費很多時間去修補,出錯的成本太高,本期我們就來看看 JDK 中那些坑你沒商量的方法,這些方法很常見,相信你一定遇到過。
        一. String.valueOf()方法的陷阱
        案發(fā)現(xiàn)場:某個鳥語花香的早上,我們在開心的敲著代碼,突然客戶群有人投訴反映,我們發(fā)給用戶的短信有部分是尊敬的 "null" 你好, xx等。
        開發(fā)第一時間看了代碼,覺的沒有問題啊,為什么短信內容會出現(xiàn)用戶名為null呢,不是經過了非空判斷的嗎?String.valueOf()是String提供的一個類型轉換的方法,我們來看一下(代碼簡化過后的):
        // 調用用戶服務根據(jù)用戶id獲取用戶信息
        Map<StringObject> userInfo = userService.getUserInfoById(userId);
        Object userNameObject = userInfo.get("name");
        String userName = String.valueOf(userNameObject);
        // 判空
        if(userName!=null&&userName.length()>0) {
            String message = getMessage(userName);
            smsService.send(message);
        }
        這段代碼是簡化過的,主要作用就是通過用戶服務根據(jù)id獲取用戶信息發(fā)送短信,后來經過定位發(fā)現(xiàn)了問題所在:首先用戶的名字里有特殊的emoji符號,數(shù)據(jù)庫寫入的時候有部分寫入失敗,因為當時的
        數(shù)據(jù)庫字符格式并無法兼容emoji,而獲取的時候因為這個問題值為null了,接下來是重點:
        這里是重點,也是最大的坑人之處,注意這里返回了一個"null"的字符串,而不是null。這兩個是有很大區(qū)別的,當進行非空判斷的時候,返回的是ture。也就是這個"null"的字符串它是符合判空條件的!
        正確的姿勢是在String.valueOf方法前必須判空:

        二. Integer.parseInt()方法很矯情

        事故現(xiàn)場:一次業(yè)務場景為拉取訂單,打出訂單列表記錄,財務人員需要拉出對賬,結果總是發(fā)現(xiàn)很奇怪的一個現(xiàn)象,每次拉取少很多數(shù)據(jù)。
        還好財務發(fā)現(xiàn)了,要不然和第三方財務對賬就會虧很多錢...最終發(fā)現(xiàn)是訂單的一個字段值轉Integer出錯了,那個訂單下的字段值是120.0通過Integer.parseInt()直接報錯了,恰好開發(fā)人員認為這段開發(fā)肯定沒問題,因此就沒有catch異常,最后找了很久才發(fā)現(xiàn)(因為涉及到第三方,還讓別人查了半天...). 知道真相的我們都有點汗顏,這么丁點的錯誤排查了很久,實在是不應該啊。
        Integer.parseInt()方法用于將字符串轉化為Integer類型的方法,此方法的適用方向就顯得比較窄,因為是String類型的參數(shù),沒有任何限定,當在傳入一些比如50.0、20L、30d、40f這類數(shù)據(jù)的情況下,
        我們來看一個栗子:
        會拋出異常NumberFormatException:
        事實上對于這樣的數(shù)據(jù),比如小數(shù)、浮點數(shù)據(jù)、long型數(shù)據(jù)它都可以自動轉換,而不是給我們拋出煩人的報錯信息,如果預先知道是整數(shù)或者小數(shù),可以用Bigdecimal轉換(注意此方法不適用于double和float、Long類型的數(shù)據(jù),比如10d,20L)
        對于浮點類型、long類型的數(shù)據(jù)可以用以下方法來處理:
        推薦使用hutool的NumberUtil.parseInt()方法,充分考慮到了浮點、long、小數(shù)等類型數(shù)據(jù)可能帶來的解析異常的問題,hutool是一個國人開源的工具類庫,這里實名推薦,容錯性和處理異常能力很強,可以自行百度搜索使用。
        三. Bigdecimal的除法坑你沒商量
        眾所周知,BigDecimal是處理金額最有效的數(shù)據(jù)類型,一般進行財務報表計算的時候為了防止金額出現(xiàn)錯誤,一般情況下都會采用Bigdecimal,而double、float都會存在些許的誤差。你開開心心的用Bigdecimal進行了計算,而最終的結果返回卻有問題,我們來看一個栗子:
        常見的除法用起來沒有任何絲毫的問題,妥妥的沒毛病.但是一旦程序中的數(shù)據(jù)出現(xiàn)以下情況,如果用Bigdecimal來接受前端的參數(shù),而前端的參數(shù)是用戶輸入不確定的,一旦出現(xiàn)如下的數(shù)據(jù),我們來看看結果:
        執(zhí)行結果一看,居然報錯了哎:
        這就是BidDecimal的坑,一旦返回的結果是無限循環(huán)小數(shù),就會拋出ArithmeticException。因此在進行Bigdecimal除法的時候,需要進行保留小數(shù)的處理,正確的處理姿勢:

        四. Collections.emptyList()此list非彼list

        我們先來看一個sample:

        public List<String> getUserNameList(String userId) {
              
              List<String> resultList = Collections.emptyList();
              try {
                  resultList = userDao.getUserName(userId);
              } catch (Exception ex) {
                  logger.info(ex);
              }
              return resultList;
          }
        這樣會拋出錯誤,主要問題在于Collections.emptyList()并非我們平時看到的List,此list不支持add、remove方法,否則會拋出operationNotSupportException:
        結果拋出異常:
        原因是:Collections.emptyList返回的并不是我們平時認識的那個list,它是一個內部常量類:
        public static final List EMPTY_LIST = new EmptyList<>();
        這個list并不具有add、remove元素的能力,我猜想是因為jdk設計之初的想法是將這個list作為一種只讀的list,并不提供數(shù)據(jù)的寫入能力,因此它僅可作為一種 空值返回,無法進行刪除、添加操作。
        五. list 可以一邊刪除一邊遍歷嗎?
        答案是肯定可以的,要不然的話list怎么刪除數(shù)據(jù)呢,不過要注意遍歷的姿勢,我們再來看一個簡單的例子:
        很不幸,又雙叒叕報錯了:
        仔細翻閱源碼會發(fā)現(xiàn),每次remove之前會檢查元素的條數(shù),如果發(fā)現(xiàn)預期的modCount和當前的modCount不一致就會拋出這個異常.modCount是list中用來記錄修改次數(shù)的一個屬性,當對元素進行統(tǒng)計的時候就會對該元素加1,而當對list邊遍歷邊刪除的話,就會造成
        excepted與modCount不一致,從而拋出異常。
        正確的刪除姿勢就是使用Iterator.remove進行遍歷刪除,可以規(guī)避這個問題。
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer integer = iterator.next();
            if (integer == 2) {
                iterator.remove();
            }

        }
        六. 總結
        JDK 的設計者有兩個很大的特點:
        1. 大多不會做非null判斷
        2. 出現(xiàn)錯誤直接throw new Exception,容錯性很差。
        在實際開發(fā)中,面對jdk一定要謹慎使用,jdk提供了便利的同時,也有一些我們使用上的盲區(qū),應該養(yǎng)成多看源碼,多注意錯誤性處理,防止在小問題上栽大跟頭。
        回到最開始說的那個subtract方法的問題,因為這個問題等需要我處理完之后用戶才能收到退款,這直接造成了用戶體驗直線下降,而部分用戶還直接打電話投訴。
        同事一個小小的不謹慎和馬虎就給公司造成了很多負面影響, 技術問題雖然不大但是帶來的業(yè)務影響范圍很嚴重。所以我們必須防微杜漸,小小的問題都得細細的打磨,才能避免很多問題的產生。
        七. 補充
        7.1 Bigdecimal在比較的時候,最好使用compareTo方法,不要使用equals方法,如下案例,雖然Bigdecimal重寫了equals方法,但是使用會存在問題:

        1和1.0在比較的時候返回了false,這是因為在equals的源碼中進行了數(shù)據(jù)的scale(也就是精度)的比較,如果不一致就會返回false,如果使用compareTo方法就不存在這個問題

        7.2  mysql的減法計算如果有null值結果就為null
        select 5-null  結果會返回null,所以在進行mysql計算的時候,對于有可能出現(xiàn)null值的列一定要進行ifnull(field,0)的轉換,將null值轉化為0,否則就會出現(xiàn)一些意想不到的數(shù)據(jù)錯誤和空指針問題:

        正確的姿勢:


        7.3.String的split方法在進行||分割的時候需要進行轉義,否則結果會有問題


        作者:Yrion

        cnblogs.com/wyq178/p/13520745.html

        END
        最近熬夜給大家準備了515套Java代碼,有一些是業(yè)務類的小項目,比如Java博客項目,也有腳手架、也有平時用一些的工具類、21套小程序代碼,也有一些游戲類的項目。

        掃以下二維碼并回復“828”即可獲取


        如下圖所示


        瀏覽 30
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩最新高清无码 | 在线中文字幕av 美女操逼免费观看 | 黑料不打烊tttzzz入口 | 天天日天天干麻豆 | 农村一级片 | www.操操网 | 久久视频黄片视频大全 | 一区二区操逼 | 操片免费| 日韩无码性爱视频 |