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