search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

如何處理Java中出現的異常?這九種方式值得一試!

[

來自IT168

]

【IT168 評論】處理 Java 中的異常情況並不是個輕鬆的話題,什麼樣的異常需要如何處理,常讓新手們覺得難以理解,甚至有經驗的開發人員也可能花幾個小時討論不決。

正因如此,大多數開發團隊有著一套自己的規則,如果你是團隊里的新人,你會對團隊之間對於這個規則的巨大差別感到驚訝。

即便是這樣,也有一些大多數團隊都使用的好做法。下面列出了 9 個比較重要的處理方式,可以幫你上手或者提升你的異常處理能力。

1、清理 Finally 塊中的資源,或使用 Try-With-Resource 語句

在 try 塊中使用資源時常發生,比如 InputStream ,是需要在用完之後關掉的。一個通常發生的錯誤是,在 try 塊的末尾關掉資源:

順利的話,只要沒有異常拋出,這種方法似乎可以工作得很好,try 中的所有語句都會被執行,然後資源也被關掉。

不過你因為某個原因添加了 try ,其中調用的一個或多個方法可能就會引發異常,甚至有可能是你自己引發了異常,此時就無法運行到 try 的結尾,結果資源沒法被關掉。

因此,你應該把清理資源的代碼都放在 finally 塊中,或者使用 Try-With-Resource 語句。

使用 finally 塊

和 try 中的最後幾行不一樣,無論是 try 塊被成功執行后還是在 catch 塊中處理了異常,finally 塊總是能被執行。這樣,你可以確保清掉所有打開的資源。

Java 7 的 Try-With-Resource 語句

另一個辦法是使用 Try-With-Resource 語句。

如果你使用的資源實現介面是 AutoCloseable,就可以用這個語句,多數Java 標準資源都這麼做。當你在 try 中打開資源,它可以在 try 執行完畢后或異常處理完后自動關閉資源。

2、更喜歡特定的異常

你引發的異常越具體越好。時刻想著那些並不知道你代碼的同伴,或者幾個月之後的你,他們需要調用你的方法處理異常。

所以,要儘可能地提供更多信息,確保你的 API 更容易理解。 這樣,調用你的方法的人才能更好地處理異常,或者避免在檢查上浪費多餘的時間。

要想辦法找到那個最合適你期望事件的類,比如引發一個 NumberFormatException 比IllegalArguementException 要好,請避免引發一個不明確的異常。

3、把指定的異常記錄下來

無論在什麼時候你在方法簽名中指定了一個異常,你都應該在你的 Javadoc 中記錄下來。這和上一個做法目的相同,都是給調用者盡量多的信息,便於他們避免或者處理異常。

所以,要確保你在 Javadoc 中添加了 @throws 申明,說明什麼樣的情況會引發異常。

4、用描述性消息引發異常

這條和前兩條背後的想法差不多,只是這次不用給方法調用者提供什麼信息了。因為日誌文件中或者監視器里收到異常報告時,每個人都必須讀取異常消息。

因此,應該儘可能準確地描述問題,並提供最相關的信息幫助了解異常事件。

請不要誤解我,我並不是讓你寫一大段文字。你應該在一兩句話中為該異常作出解釋,這能幫助你的運維團隊了解問題的嚴重程度,同時也讓你在分析服務異常時更輕鬆。

如果你引發了一個特定的異常,它的類名就可能已經描述了錯誤類型,所以你也不用再提供更多信息了。NumberFormatException 是個比較好的例子,當你在給一個字元串提供了錯的格式,類 java.lang.Long 的構造函數就會引發這個異常。

NumberFormatException,這個名字已經告訴你問題所在了,你只需要提供導致問題的字元串。如果異常類的名稱不具有表達性,需要在消息中提供所需的信息。

5、優先抓住最具體的異常

多數 IDE 可以幫助你實現這一條。 當你在嘗試優先捕獲較少特定的異常時,它們會報告一個無法訪問的代碼塊。

問題在於,只有與異常匹配的第一個 catch 塊會被執行,如果你先抓住了 IllegalArgumentException,你就無法到達應該處理更具體的 NumberFormatException,因為NumberFormatException 是其子類。

總是優先捕獲最具體的異常類,並將低精確度的 catch 塊添加到列表末尾。

在以下代碼段中,你可以看到一個這樣的 try-catch 語句的示例。第一 catch 塊處理所有的NumberFormatException,第二個則是處理所有非 NumberFormatException 的IllegalArgumentException。

6、別去抓可拋出的對象

可拋出(throwable)是所有異常和錯誤的超類,雖然你可以在 catch 語句中使用,但是你永遠都不應該用它。

如果你在 catch 語句中使用可拋出對象,結果不僅僅是抓住所有的異常,它還會抓出所有的錯誤。錯誤由 JVM 拋出,會指出那些不打算被應用程序處理的嚴重問題。這一類型的代表例子是 OutOfMemoryError,以及 StackOverflowError,兩者都是由不在應用控制之內的情況引發的,無法處理。

所以,除非你絕對確定處於異常情況下,並且你有能力或被要求去處理錯誤,否則不要去抓可拋出對象。

7、不要忽視異常

你有沒有分析過一個只有用例的第一部分被執行了的錯誤報告?

這種情況的原因往往是一個被忽視的異常,那個開發者可能非常確定它不會再被拋出,還添加了一個並不能處理或者記錄異常的 catch 塊。然後,當你發現這個塊時,你還很有可能找到一個名為「永遠不會發生」的著名評論。

你當然有可能在分析一個會發生不可能的問題。

所以,不要忽視一個異常。你不知道代碼將來會發生怎樣的改變,可能有人會刪除你用來防止異常事件的驗證,全然不知這會導致問題。或者,拋出異常的代碼被修改,導致在同一個類里拋出多個異常,而且調用代碼也不能阻止所有的異常了。

你至少應該寫一個日誌消息,告訴大家發生了難以想象的事情,需要有人做檢查。

8、別記錄完又拋出

這一條可能是這個列表中最常被忽視的。不過,你總是能找到很多代碼段甚至是庫里,有異常被捕獲、記錄然後又拋出。

一般大家的直覺是,異常發生時記錄它然後再把它拋出,這樣可以方便調用者妥善處理該異常。可問題是往往大家會為同一個異常寫入多個錯誤消息。

而且后添加的消息沒有任何其他信息。我們在 第 4 條里說過,異常消息應該描述異常事件。然後堆棧跟蹤會告訴你拋出異常的是哪個類,那種方法和哪一行。

如果你需要添加更多的信息,應該捕獲異常並把它打包在一個自定義的信息中。 但請務必遵循第 9 條。

所以,只有在你想處理該異常時再捕獲它。否則就在方法簽名中指明它,讓調用者去處理。

9、在不損耗異常的情況下打包它

有時,抓住標準的異常並將其打包到自定義異常中更好。比較典型的是應用程序或框架特定的業務異常,你可以添加其他信息,還可以為異常類執行特殊處理。

這樣做的過程中,要確保把原始的異常設置為原因(異常類提供了一個特定的構造函數用來接受可拋出對象作為參數)。不這樣做的話,原始異常的堆棧跟蹤和消息就會丟失,導致異常的事件難以分析。

總結

如你所見,在你拋出或捕獲異常的時候,應該考慮很多不同的事情,其中大多數都是為了提高代碼的可讀性或 API 的可用性。

異常通常是由一個錯誤的處理機制和同時使用的溝通媒介導致的。因此,你應該和同事討論你要用的做法和規則,讓每個人都理解通用的概念,然後用相同的方式執行這些做法和規則。



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦