在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

簡述那些JDK中坑你沒商量的方法

電子工程師 ? 來源:博客園 ? 作者:Yrion ? 2021-06-12 17:36 ? 次閱讀

前言

JDK 作為我們每天必備的調用類庫,里面大量提供了基礎類供我們使用。可以說離開 JDK ,我們的 Java代碼寸步難行。

JDK 帶給我們的便利可謂是不勝枚舉,但同時這些方法在使用起來也存在一些坑,如果不注意就很容易掉入到陷阱里面,導致程序拋出錯誤。

JDK 中的很多方法都不會做非 null 判斷,可能設計 JDK 的作者默認開發者已經處理好 null 值了。不過這個設計可能會造成很嚴重的后果,實在是暗藏殺機。比如,今天早上我們查了一筆訂單沒有退款,查了一早上最終才發現是同事寫的代碼的 BigDecimal 的 subtract 方法的值沒有做非 null 判斷處理導致程序拋出了空指針異常。

看似簡單的異常卻直接無法讓很多訂單退款,實在是小問題造成大事故。而要修補退款這個問題,要耗費很多時間去修補,出錯的成本太高。

本文就來看看 JDK 中那些坑你沒商量的方法,這些方法很常見,相信你一定遇到過。

1 String.valueOf() 方法的陷阱

案發現場

某個鳥語花香的早上,我們在開心的敲著代碼,突然客戶群有人投訴反映:我們發給用戶的短信有部分是尊敬的 “null” 你好,等等。

開發第一時間看了代碼,覺得沒有問題啊。為什么短信內容會出現用戶名為 null 呢?不是經過了非空判斷的嗎?String.valueOf() 是 String 提供的一個類型轉換的方法,我們來看一下(代碼經過了簡化):

// 調用用戶服務根據用戶id獲取用戶信息Map《String, Object》 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);}

這段代碼是簡化過的,主要作用就是通過用戶服務根據 id 獲取用戶信息發送短信。

后來經過定位發現了問題所在:首先,用戶的名字里有特殊的 emoji 符號。數據庫寫入的時候有部分寫入失敗。因為當時的數據庫字符格式并無法兼容 emoji,而獲取的時候因為這個問題值為 null 了。

接下來是重點:

public static String valueOf(Object obj) { return (obj == null) ? “null” : obj.toString();}

這里是重點,也是最大的坑。

注意:這里返回了一個 “null” 的字符串,而不是 null。這兩個是有很大區別的。當進行非空判斷的時候,返回的是 true。也就是這個 “null” 字符串是符合判空條件的!

正確的姿勢是在 String.valueOf 方法前必須判空:

if (userNameObject != null) { String userName = userNameObject.toString();}

2 Integer.parseInt() 方法很矯情

事故現場

業務場景為拉取訂單,打出訂單列表記錄。財務人員需要拉出對賬,結果總是發現很奇怪的一個現象:每次拉取少很多數據。還好財務發現了,要不然和第三方財務對賬就會虧很多錢。

最終發現,是訂單的一個字段值轉 Integer 出錯了。那個訂單下的字段值是 120.0,通過 Integer.parseInt() 直接報錯了。恰好開發人員認為這段開發肯定沒問題,因此就沒有 catch 異常。最后找了很久才發現,因為涉及到第三方,還讓別人查了半天……

知道真相的我們都有點汗顏:這么丁點的錯誤排查了很久,實在是不應該啊。

Integer.parseInt() 方法用于將字符串轉化為 Integer 類型的方法。此方法的適用性就顯得比較窄,因為是 String 類型的參數沒有任何限定,當在傳入一些比如 50.0、20L、30d、40f 這類數據的情況下會拋出異常。

我們來看一個例子:

String input = “50.0”;int out = Integer.parseInt(input);

會拋出異常 NumberFormatException:

740e2dd4-c7a3-11eb-9e57-12bb97331649.png

事實上對于這樣的數據,比如小數、float、double、long 類型數據都可以自動轉換,而不是給我們拋出煩人的報錯信息。如果預先知道是整數或者小數,可以用 BigDecimal 轉換。

注意:此方法不適用于 double、float、Long 類型的數據,比如10d、20L。

String input = “50.0”;int out2 = new BigDecimal(input).intValue();System.out.println(out2);

對于 float、long 類型的數據可以用以下方法來處理:

推薦使用 hutool 的 NumberUtil.parseInt() 方法。充分考慮到了 float、double、long、小數等類型數據可能帶來的解析異常的問題。hutool 是一個國人開源的工具類庫,這里強烈推薦,容錯性和處理異常能力很強。

3 BigDecimal 的除法坑你沒商量

眾所周知,BigDecimal 是處理金額最有效的數據類型。一般進行財務報表計算的時候為了防止金額出現錯誤,一般情況下都會采用 BigDecimal。而 double、float 都會存在些許的誤差。你開開心心地用 BigDecimal 進行了計算,而最終的結果返回卻有問題。我們來看一個例子:

BigDecimal ten = new BigDecimal(10);BigDecimal two= new BigDecimal(2);BigDecimal result = ten.divide(two);System.out.println(result.toString());

常見的除法用起來沒有任何絲毫的問題,妥妥的沒毛病。但是一旦程序中的數據出現以下情況,如果用 BigDecimal 來接受前端的參數。而前端的參數是用戶輸入不確定的,一旦出現如下的數據,我們來看看結果:

BigDecimal ten = new BigDecimal(10);BigDecimal three= new BigDecimal(3);BigDecimal result = ten.divide(three);System.out.println(result.toString());

執行結果一看,居然報錯了:

74596fc4-c7a3-11eb-9e57-12bb97331649.png

這就是 BigDecimal 的坑:一旦返回的結果是無限循環小數,就會拋出 ArithmeticException。因此在進行 BigDecimal 除法的時候,需要進行保留小數的處理。

正確的處理姿勢:

BigDecimal ten = new BigDecimal(10);BigDecimal three= new BigDecimal(3);BigDecimal result = ten.divide(three, 2, BigDecimal.ROUND_HALF_UP);System.out.println(result.toString());

4 Collections.emptyList() 此 List 非彼 List

我們先來看一個例子:

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。

List《String》 resultList = Collections.emptyList();resultList.add(“test”);

結果拋出異常:

74631236-c7a3-11eb-9e57-12bb97331649.png

原因是 Collections.emptyList 返回的并不是我們平時認識的那個 List,它是一個內部常量類:

public static final List EMPTY_LIST = new EmptyList《》();

這個 List 并不具有 add、remove 元素的能力。我猜想是因為 JDK 設計之初的想法是將這個 List 作為一種只讀的 List ,并不提供數據的寫入能力。因此它僅可作為一種空值返回,無法進行刪除、添加操作。

5 List 可以一邊刪除一邊遍歷嗎?

答案是肯定可以的。要不然的話 List 怎么刪除數據呢?不過要注意遍歷的姿勢,我們再來看一個簡單的例子:

public static void main(String[] args) { List《Integer》 resultList = new ArrayList《》(); resultList.add(1); resultList.add(2); resultList.add(3); for (Integer num : resultList) { if (num == 1) { resultList.remove(num); } }}

很不幸,又雙叒叕報錯了:

746f0c62-c7a3-11eb-9e57-12bb97331649.png

仔細翻閱源碼會發現,每次 remove 之前會檢查元素的條數。如果發現預期的 modCount 和當前的 modCount 不一致就會拋出這個異常。modCount 是 List 中用來記錄修改次數的一個屬性,當對元素進行統計的時候就會對該元素加 1。而當對 List 邊遍歷邊刪除的話,就會造成 excepted 與 modCount 不一致,從而拋出異常。

final void checkForModification() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); }}

正確的刪除姿勢就是使用 Iterator.remove 進行遍歷刪除,可以規避這個問題。

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

6 總結

JDK 的設計者有兩個很大的特點:

大多不會做非 null 判斷;

出現錯誤直接 throw new Exception,容錯性很差。

在實際開發中,面對 JDK 一定要謹慎使用。JDK 提供了便利的同時,也有一些我們使用上的盲區。應該養成多看源碼,多注意錯誤性處理,防止在小問題上栽大跟頭。

回到最開始說的那個 subtract 方法的問題,因為這個問題等需要我處理完之后用戶才能收到退款,這直接造成了用戶體驗直線下降,而部分用戶還直接打電話投訴。同事一個小小的不謹慎和馬虎就給公司造成了很多負面影響,技術問題雖然不大但是帶來的業務影響范圍很嚴重。

所以我們必須防微杜漸,小小的問題都得細細的打磨,才能避免很多問題的產生。

7 持續更新

7.1 BigDecimal 在比較的時候最好使用 compareTo 方法,不要使用 equals 方法

如下案例。雖然 BigDecimal 重寫了 equals 方法,但是使用會存在問題:

public static void main(String[] args) { System.out.println(new BigDecimal(“1”).equals(new BigDecimal(“1.0”)));}

D:jdkbinjava.exe 。。.false

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

7.2 MySQL 減法計算,如果有 null 值結果就為 null

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

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

String str = “77||88”;final String[] split1 = str.split(“||”);final String[] split2 = str.split(“\|\|”);

System.out.print(“錯誤的分割方式:”);for (String s : split1) { System.out.print(s + “ ”);}System.out.print(“

”);

System.out.print(“正確的分割方式:”);for (String s : split2) { System.out.print(s + “ ”);}

錯誤的分割方式:7 7 | | 8 8 |正確的分割方式:77 88

轉自:Yrion,

鏈接:cnblogs.com/wyq178/p/13520745.html

編輯:jq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    19

    文章

    2976

    瀏覽量

    105216
  • 代碼
    +關注

    關注

    30

    文章

    4837

    瀏覽量

    69123
  • JDK
    JDK
    +關注

    關注

    0

    文章

    82

    瀏覽量

    16637

原文標題:那些JDK中坑你沒商量的方法

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    被問爆的避方法!——天線設計

    天線設計,也是4G模組應用中最容易踩的地方。今天主要分享討論Air700ECQ/EAQ/EMQ系列模組,天線管腳到4G天線之間的電路設計和走線規則。 ? Air700ECQ/EAQ/EMQ模組屬于
    的頭像 發表于 12-26 16:45 ?271次閱讀
    被問爆的避<b class='flag-5'>坑</b><b class='flag-5'>方法</b>!——天線設計

    開關電源紋波噪聲產生原因和測試方法

    本文簡述了開關電源紋波噪聲測試方法及延伸,同時分享紋波噪聲測試使用設備,以及給出紋波噪聲測試的具體方法,供大家學習參考。
    的頭像 發表于 12-20 09:39 ?1825次閱讀
    開關電源紋波噪聲產生原因和測試<b class='flag-5'>方法</b>

    電源設計避(下)

    。在上一期《電源設計避(上)》,我們討論了電源設計的電源功率、穩定性、紋波控制以及尖峰和浪涌的問題,并結合實際案例提出了相應的應對措施。接下來,我們將繼續探索
    的頭像 發表于 12-16 11:37 ?367次閱讀
    電源設計避<b class='flag-5'>坑</b>(下)

    幾個最為常見的放大器電路設計問題,掉過嗎?

    的直流電壓的一種簡單方法。這種方法在高增益應用尤為有用,在增益較高時,即使是放大器輸入端的一個較小直流電壓,也會影響運放的動態范圍,甚至可能導致輸出飽和。然而,容性耦合進高阻抗輸入端而不為正輸入端
    發表于 10-14 10:32

    商湯日日新·商量-擬人大模型帶你對話未來,感受真實

    對此,專注于“擬人對話”領域的商量-擬人大模型(SenseChat-Character)應運而生,通過實現精準人設展現以及具有沉浸感的交互,讓智能體更像栩栩如生的人。
    的頭像 發表于 09-18 15:57 ?724次閱讀

    簡述開關電源兩類漏電流的區別

    引言:在日常工作,硬件設計工程師朋友們經常會接觸到漏電流這個指標,其分為泄漏電流和耐壓漏電流。本文將簡述開關電源兩類漏電流的區別,并簡要分析了常見漏電流異常的問題,同時給出了對應的驗證方法和解決及預防的辦法,保障系統可靠性。
    的頭像 發表于 08-06 15:24 ?1420次閱讀
    <b class='flag-5'>簡述</b>開關電源兩類漏電流的區別

    簡述半導體原理——晶體管家族的核心工作機制

    簡述半導體原理——晶體管家族的核心工作機制
    的頭像 發表于 07-20 08:14 ?1098次閱讀
    <b class='flag-5'>簡述</b>半導體原理——晶體管家族的核心工作機制

    Python那些

    問題來了,這三組代碼的運行結果分別是什么呢?答案是True、False和True。第一組和第三組結果是True好像沒問題,那為什么第二組的結果是False呢?這里先用id()來查看一下a和b的地址是什么。
    的頭像 發表于 07-16 17:52 ?396次閱讀

    JDK8升級JDK11最全實踐干貨來了

    1、前言 截至目前(2023年),Java8發布至今已有9年,2018年9月25日,Oracle發布了Java11,這是Java8之后的首個LTS版本。那么從JDK8到JDK11,到底帶來了哪些特性
    的頭像 發表于 06-25 14:51 ?536次閱讀
    <b class='flag-5'>JDK</b>8升級<b class='flag-5'>JDK</b>11最全實踐干貨來了

    JDK11升級JDK17最全實踐干貨來了

    1、前言 如果仍在使用JDK8,那你是否曾經遇到過OutOfMemoryError的問題?是否曾經為JVM的調優問題感到困擾?本篇文章將為介紹一種能夠提供百倍性能提升的垃圾回收器
    的頭像 發表于 06-25 14:50 ?818次閱讀
    <b class='flag-5'>JDK</b>11升級<b class='flag-5'>JDK</b>17最全實踐干貨來了

    凱迪正大對110kV電力電纜交接試驗的重要性與實施方法簡述

    確保其在實際運行能夠穩定可靠地工作,保障電網運行的安全和可靠性。本文將從110kV電力電纜交接試驗的重要性入手,按照武漢凱迪正大的實操經驗簡述其試驗方法及實施過程。
    的頭像 發表于 06-18 17:19 ?535次閱讀
    凱迪正大對110kV電力電纜交接試驗的重要性與實施<b class='flag-5'>方法</b><b class='flag-5'>簡述</b>

    商湯科技發布“商量”粵語版大模型

    商湯科技近日發布了針對粵語用戶量身定制的商量語言大模型和商量多模態大模型。這兩款模型即日起向企業用戶開放API接口,同時Web版和App版也將很快向粵語區用戶免費推出,以滿足廣大用戶的多樣化需求。
    的頭像 發表于 05-31 10:52 ?1040次閱讀

    家庭路由器如何選?實用技巧讓不再踩

    家庭路由器選購需考慮需求、預算、性能指標、硬件配置、軟件功能、認證與測試及售后服務。明確需求,選擇適合的型號和品牌,確保網絡穩定、高速。遵循這些技巧,避免踩,享受網絡便利。
    的頭像 發表于 04-29 11:38 ?865次閱讀

    輥壓機軸承位磨損修復不知道的那些

    電子發燒友網站提供《輥壓機軸承位磨損修復不知道的那些事.docx》資料免費下載
    發表于 03-12 15:10 ?0次下載

    背散SEM那些位置是硅的顆粒?

    如下硅與石墨復配的負極材料的背散SEM,圓圈標的地方是硅嗎?如果不是還請大佬指點一下,那些位置是硅?
    發表于 03-12 08:53
    主站蜘蛛池模板: 又长又大又粗又硬3p免费视 | 激情狠狠干| 亚洲毛片网 | 婷婷资源综合 | 人人公开免费超级碰碰碰视频 | tdg58在线观看| 色妞色综合久久夜夜 | 黄色国产视频 | 天天草夜夜操 | 亚洲一区中文字幕在线 | 伊人天伊人天天网综合视频 | 特级毛片aaaa免费观看 | 给个网站可以在线观看你懂的 | 亚洲人与牲动交xxxxbbbb | 国产精品女仆装在线播放 | 永久免费人成网ww555kkk手机 | 色老头永久免费网站 | 五月天婷婷丁香中文在线观看 | 国产成人黄网址在线视频 | 六月丁香啪啪 | 成人国产在线24小时播放视频 | 2019天天操天天干天天透 | 老司机精品视频免费 | 女的扒开尿口让男人桶爽 | 国产午夜精品久久理论片小说 | 天天精品 | 久久婷婷激情综合色综合也去 | 激情五月深爱五月 | 日日射夜夜 | 人与牲动交xxxxbbb | 婷婷六月丁| 午夜国产精品免费观看 | 午夜高清在线观看免费6 | 四虎影视4hu4虎成人 | 2019天天射干 | 激情免费视频 | 免费看黄色片网站 | 午夜影视啪啪免费体验区深夜 | 在线观看色视频网站 | dvd碟片色爱 | 午夜观看 |