1. 程式人生 > 實用技巧 >NullPointerException 的處理新方式,Java14 真的太香了!

NullPointerException 的處理新方式,Java14 真的太香了!

在Java語言中,處理空指標往往是一件很頭疼的事情,一不小心,說不定就搞出個線上Bug,讓你的績效考核拿到3.25。

最近新出的Java14,相信大家都有所耳聞,那麼今天就來看看,面對NullPointerException,Java14有哪些更好的處理方式呢?

1.傳統的 NullPointerException

我們編碼過程中呢,經常會使用鏈式呼叫的方式來寫程式碼,這樣寫起來很方便,也很清晰,但是,一旦出現NullPointerException,那就頭大了,因為你很難知道異常是在什麼時候開始發生的。

舉個簡單的例子,就比如下面的程式碼,要找到公司某個員工的戶籍所在地,我們這樣來呼叫

String city = employee.getDetailInfos().getRegistryAddress().getCity();

在鏈式呼叫的過程中,如果employee, getDetailInfos(),或者 getRegistryAddress() 為空,JVM就會丟擲 NullPointerException

那麼導致異常的根本原因是什麼?如果不使用偵錯程式,很難確定哪個變數為空。而且,JVM也只會列印導致異常的方法、檔名和行號,僅此而已。那麼下面,我將帶大家瞭解Java 14如何通過 JEP 358 解決這個問題。

2.增強型 NullPointerException

SAP在2006年為其商業JVM實現了增強型的 NullPointerException。2019年2月,它被提議作為OpenJDK社群的一個增強,之後很快,它成為了一個JEP。所以,該功能在2019年10月完成並在JDK 14版本推出。

本質上,JEP 358 旨在通過描述某個變數是 “null” 來提高 JVM 生成的 “NullPointerException” 的可讀性。JEP 358通過在方法、檔名和行號旁邊描述為 null 的變數,帶來了一個詳細的 NullPointerException 訊息。它通過分析程式的位元組碼指令來工作。因此,它能夠精確地確定哪個變數或表示式是null。最重要的是,JDK 14中預設關閉詳細的異常訊息。要啟用它,我們需要使用命令列選項:

-XX:+ShowCodeDetailsInExceptionMessages

2.1 詳細的異常資訊
考慮在啟用 ShowCodeDetailsInExceptionMessages 標誌的情況下再次執行程式碼:

Exception in thread "main" java.lang.NullPointerException:
  Cannot invoke "RegistryAddress.getCity()" because the return value of
"com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException$DetailInfos.getRegistryAddress()" is null
  at com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException.main(HelpfulNullPointerException.java:10)

這一次,從附加資訊中,我們知道員工的個人詳細資訊丟失的註冊地址導致了我們的異常。從這個增強中獲得的資訊可以節省我們除錯所用的時間。
JVM由兩部分組成詳細的異常訊息。第一部分表示失敗的操作,這是引用為 null 的結果,而第二部分標識了 null 引用的原因:

Cannot invoke "String.toLowerCase()" because the return value of "getEmailAddress()" is null

為了生成異常訊息,JEP 358 重構了將空引用推送到運算元堆疊上的部分原始碼。

3. 技術方面

現在我們已經很好地理解了如何使用增強的NullPointerExceptions標識 null 引用,讓我們來看看它的一些技術方面。

首先,只有當JVM本身丟擲一個 NullPointerException 時,才會進行詳細的訊息計算,如果我們在Java程式碼中顯式丟擲異常,則不會執行計算。原因是因為:在這些情況下,很可能已經在異常建構函式中傳遞了一條有意義的訊息。

其次,**JEP 358 ** 懶漢式地計算訊息,這意味著只有當我們列印異常訊息時才呼叫增強的NullPointerException,而不是當異常發生時就呼叫。因此,對於通常的JVM流程不應該有任何效能影響,在那裡我們可以捕獲並重新丟擲異常,因為咱並不會只想列印異常訊息。

最後,詳細的異常訊息可能包含原始碼中的區域性變數名。因此,我們可以認為這是一個潛在的安全風險。但是,只有在執行使用啟用的 -g 標記編譯的程式碼時,才會發生這種情況,該標記會生成除錯資訊並將其新增到類檔案中。請考慮一個簡單的示例,我們已編譯該示例以包含以下附加除錯資訊:

Employee employee = null;
employee.getName();

當執行以上程式碼時,異常資訊中會列印本地變數名稱:

"com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException$Employee.getName()"
because "employee" is null

相反,在沒有額外除錯資訊的情況下,JVM 只提供它在詳細訊息中所知道的變數:

Cannot invoke
  "com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException$Employee.getName()"
because "<local1>" is null

JVM 列印編譯器分配的變數索引,而不是本地變數名(employee)。

關於NullPointerException的處理到這裡就結束了,通過Java14增強的NullPointerException,我們可以很快速的定位程式碼問題的原因所在,更快的除錯程式碼,節約時間,提高效率。

已經安裝了Java14的朋友可以試試看哦~

來源:鍋外的大佬

歡迎關注我的微信公眾號「碼農突圍」,分享Python、Java、大資料、機器學習、人工智慧等技術,關注碼農技術提升•職場突圍•思維躍遷,20萬+碼農成長充電第一站,陪有夢想的你一起成長