Java 異常處理


相信了解 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ì)英文文章。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 六種異常處理的陋習(xí) 你覺得自己是一個(gè)Java專家嗎?是否肯定自己已經(jīng)全面掌握了Java的異常處理機(jī)制?在下面這段代...
    Executing閱讀 1,410評(píng)論 0 6
  • Java異常類型 所有異常類型都是Throwable的子類,Throwable把異常分成兩個(gè)不同分支的子類Erro...
    予別她閱讀 1,030評(píng)論 0 2
  • 初識(shí)異常(Exception) 比如我們?cè)谌?shù)組里面的某個(gè)值得時(shí)候,經(jīng)常會(huì)出現(xiàn)定義的取值范圍超過了數(shù)組的大小,那么...
    iDaniel閱讀 1,966評(píng)論 1 2
  • 概念介紹 異常是發(fā)生在程序執(zhí)行過程中阻礙程序正常執(zhí)行的錯(cuò)誤事件,當(dāng)一個(gè)程序出現(xiàn)錯(cuò)誤時(shí),可能的情況有如下3種: 語(yǔ)法...
    niaoge2016閱讀 5,613評(píng)論 2 20
  • 這周老師的功課有一個(gè)主題是關(guān)于這一個(gè)。覺察自己想炫耀,希望別人贊美自己的虛榮我執(zhí)。 其實(shí),我早就看到自己有...
    喜悅能量沙沙閱讀 326評(píng)論 0 2

友情鏈接更多精彩內(nèi)容