關於Java編程,你知道嗎?異常處理的兩個基本原則

先來看一段代碼:

try {

// do something

Thread.sleep(1000L);

} catch (Exception e) {

// ignore it

}

代碼雖短,但已經違反了異常處理的兩個基本原則。

第一,儘量不要捕獲類似Exception這樣的通用異常,而是應該捕獲特定異常。在這段代碼中Thread.sleep()會拋出的InterruptedException。

在日常的開發合作中,我們讀代碼的機會往往會超過寫代碼,軟件工程是門協作的藝術。所以我們有義務讓自己的代碼能夠直觀地體現出儘量多的信息。在這段代碼中只是泛泛地使用了Exception,隱藏了我們的目的。

另外,我們也要保證程序不會捕獲到我們不希望捕獲的異常。比如一些非檢查型異常(RuntimeException的子類,是否還記得“關於Java,你知道嗎(1)”?原文請查看文末鏈接),此時你可能更希望將其擴散,而非捕獲。

進一步講,除非你已經深思熟慮,否則不要捕獲Throwable或者Error,你確定你能夠處理OutOfMemoryError這樣的異常麼?

第二,不要生吞異常。這是異常處理中要特別注意的事情,因爲很可能會導致非常難以診斷的詭異情況。

生吞異常,往往是基於假設這段代碼可能不會發生,或者感覺忽略異常時無所謂的,但是千萬不要在產品代碼做這種假設!如果我們不把異常拋出來,或者也沒有輸出到日誌(Logger),程序可能在後續代碼以不可控的方式結束。沒人可以輕易判斷是哪裏拋出了異常,以及是什麼原因產生了異常。

再來看看下面這段代碼:

try {

// do something

} catch (IOException e) {

e.printStackTrace();

}

上面這段代碼如果出現在實驗代碼中,沒有任何問題,但如果出現產品代碼中,通常都不允許這樣處理。

這是爲什麼呢?

(不妨先思考一下再往下看)

printStackTrace()的文檔開頭有這樣一段描述:“Prints this throwable and its backtrace to the standard error stream”。

問題就在這裏,在稍微複雜一點的生產系統中,標準出錯(STERR)不是個合適的輸出選項,因爲你很難判斷到底輸出到哪裏去了。尤其是對於分佈式系統,如果發生異常,但是因此無法找到堆棧軌跡,這純屬爲診斷設置障礙。所以,最好的選擇就是輸出到產品日誌中。

相關文章