(給ImportNew加星標,提高Java技能)
來自:唐尤華
dzone.com/articles/good-exception-handling
像冠軍一樣處理異常。
哦,請不要這樣寫……
// 寫一句註釋跳過異常
try {
throw new IOException("Made up");
} catch (IOException e) {
// 跳過
}
// 記到日誌裡,繼續處理
try {
throw new IOException("Made up");
} catch (IOException e) {
log.error("blah blah blah", e);
}
// 標記 TODO,不做任何處理
try {
throw new IOException("Made up");
} catch (IOException e) {
// TODO - 處理異常 (;
}
我在各種專案中發現了這種 catch 陳述句。這是一種“好辦法”,可以在短期內掩蓋問題。然而幾周或幾個月後,這些程式碼將成為開發人員的噩夢。 絕大多數人可不想讀日誌查問題。 因此,還是讓我們避免這種情況。
規則一:catch 陳述句是用來處理異常的,把異常記到日誌裡然後繼續執行不算處理。唯一的例外是,在發生異常後關閉資源(本文不討論這種情況;如果感興趣,可以參考這篇 McDowell 的部落格,雖然寫的時間比較早,但內容很不錯)。
有三種處理異常的基本樣式:轉換(translate)、重試(retry)和恢復(recover)。
轉換經常用於處理受檢異常(checked exception),在方法中異常無法丟擲,並且無法恢復時使用。 在這種情況下,將其轉換為執行時異常(runtime exception)而後丟擲是最合適的做法。接下來,執行時異常通常由框架處理。 在處理不可靠的服務時,重試非常有用,前提是重新嘗試有意義。一個很好的例子就是網路中斷重試。如果定義了這種策略,那麼就能夠恢復到正常狀態。例如,如果透過網路傳送資料失敗,可以將資料寫入本地儲存。當然,這時就必須定義如何處理該檔案。
此外,上面提到的樣式可以組合,比如像下麵這個例子如下。
// 轉換
try {
throw new IOException("Made up");
} catch (IOException e) {
throw new RuntimeException(e);
}
// 重試5次後放棄
boolean end = false;
int count = 0;
while (end == false) {
try {
// 傳送資訊
if (true) {
throw new MessagingException("Made up");
}
end = true;
} catch (MessagingException e) {
if (count >= 5) {
// 嘗試5次放棄。
throw new RuntimeException("was not able to send message even after five tries", e);
}
++count;
try {
Thread.sleep(30000);
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
throw new RuntimeException(e1);
}
}
}
// 恢復:如果傳輸失敗記錄到檔案
try {
// 傳送資訊
throw new MessagingException("Made up");
} catch (MessagingException e) {
try {
// 寫檔案
throw new IOException("Made up");
} catch (IOException e1) {
// 如果寫檔案失敗,不再進行恢復
throw new RuntimeException(e1);
}
}
如果一切都失敗了,那麼上面這種方法至少可以確保你能意識到問題所在。 此外,它還提供了問題的真正原因,從而讓你能快速定位問題。
祝程式設計快樂!