Java 異常處理
相信了解 Java 的人對于通過 try-catch-finally 來處理異常應該都有所了解了。但可能很多人在實際中還只是僅僅將代碼包起來,然后在 catch 中輸出錯誤信息而已。但是 Java 的異常處理其實也可以簡潔、優雅。
基礎
Java 中的異常處理都是圍繞著 try-catch-finally, throw, throws 這幾個展開的,也就是:
- try-catch-finally:捕獲異常并處理。
- throw:遇到錯誤的時候拋出一個異常。
- throws:聲明一個方法可能拋出的異常(所有可能拋出的異常都需要聲明)。
在 Java 中的異常分為 checked exception 和 unchecked exception。
java.lang.RuntimeException 和 java.lang.Error 類及其子類是 unchecked exception,其余的就是 checked exception 了。
當你在進行 API 設計時,必須要了解到異常聲明也是 API 的一部分。如果你為你公開的 API 聲明了可能拋出的異常,在今后很長的一段時間里你可能都甩不掉它們了。以后你要重構或進一步開發這些 API 時,不得不考慮這些異常帶來的向后兼容性問題。因為,如果你在日后的版本中刪除了某個異常的聲明,就會造成之前用戶的代碼無法通過編譯。
仔細考慮你要聲明拋出的異常。
異常處理
異常處理的難點主要是在對于什么時候處理異常的理解上。在不同的層級上,你要考慮這個異常是不是應該在這個層級上進行處理,還是說應該繼續向上拋出,甚至某些情況下還需要包裝捕獲到的異常,再向上拋出。
不同抽象層級上的代碼應該只聲明拋出同一層級上的異常。
就像處理界面的代碼不應該還會捕獲處理數據庫操作的異常一樣。 為了避免這個問題,更高層次的實現需要捕獲低層次的異常,包裝之后再拋出屬于更高層次的異常。這種做法被稱作:Exception translation。
try {
...
} catch(LowerLevelException e) {
throw new HigherLevelException(...);
}
當然最完美的情況還是完美的層次設計,在調用低層級的方法之前確保它們無論如何都能成功執行,從根本上避免低層拋出異常。實在避免不了,再使用 exception translation。
在具體處理異常的地方,應當使 try-catch 塊盡可能的小,catch 盡可能具體的異常。千萬不要 catch Exception 這么寬泛的異常之后就不管了。嘗試把 try-catch 作為程序流程控制的一部分。
比如:
String parm;
try {
param = jsonObj.getString("parm");
} catch (JSONException e) {
e.printStackTrace();
param = "default value"; // 設置一個默認值。
}
// Use param.
這也隱含了一個準則: 不要忽略異常 。忽略異常最簡單的一個方法就是使用一個空的 catch。即使你確定什么都不需要做,至少也要包含一條記錄,解釋為什么可以什么都不做。
如果你需要自己創建異常,請將對異常的設計放在與程序設計同樣的地位。有的開發者可能會用一個大而全的異常類來表示各種不同類型的錯誤,只用錯誤信息來區分不同的錯誤。這種異常處理方式一方面是不夠優雅,另一方面是當你需要進行 exception translation 時很難對這種大而全的異常進行再包裝。
你應該仔細設計異常的層次結構,根據不同的抽象定義不同的異常類,并在異常類中包含盡量豐富的信息。對于異常提供的信息來說,是程序的內部錯誤,要和展示給用戶的錯誤提示區分開來。因此,程序需要保證在和用戶交互的層次上,捕獲所有的異常,并生成相應的面向用戶的錯誤提示。
這里只分享了異常處理中的一些原則和思想,如果想了解具體的實踐方法可以閱讀最后的參考資料。: )
參考資料:
- Exception handling
- 深入理解 Java 7:核心技術與最佳實踐
- Effective Java (2nd edition)
來自:https://zhuanlan.zhihu.com/p/24043941