Java 異常處理的誤區和經驗總結
阿新 • • 發佈:2018-05-14
ORC 進一步 相關 ror final 額外 檢測 業務 清理資源
一 異常分檢測異常和非檢測異常,異常的應用情景可以概括為以下:
- 調用代碼不能繼續執行,需要立即終止。出現這種情況的可能性太多太多,例如服務器連接不上、參數不正確等。這些時候都適用非檢測異常,不需要調用代碼的顯式捕捉和處理,而且代碼簡潔明了。
- 調用代碼需要進一步處理和恢復。假如將 SQLException 定義為非檢測異常,這樣操作數據時開發人員理所當然的認為 SQLException 不需要調用代碼的顯式捕捉和處理,進而會導致嚴重的 Connection 不關閉、Transaction 不回滾、DB 中出現臟數據等情況,正因為 SQLException 定義為檢測異常,才會驅使開發人員去顯式捕捉,並且在代碼產生異常後清理資源。當然清理資源後,可以繼續拋出非檢測異常,阻止程序的執行。根據觀察和理解,檢測異常大多可以應用於工具類中。
二 不要將異常直接顯示在頁面或客戶端
何異常都沒有實際意義,絕大多數的客戶也根本看不懂異常信息,軟件開發也要盡量避免將異常直接呈現給用戶。
三 不要用異常汙染代碼的層次結構
public Customer retrieveCustomerById(Long id) throw SQLException { //根據 ID 查詢數據庫 }
從設計耦合角度仔細考慮一下,這裏的 SQLException 汙染到了上層調用代碼,調用層需要顯式的利用 try-catch 捕捉,或者向更上層次進一步拋出。根據設計隔離原則,我們可以適當修改成:
public Customer retrieveCustomerById(Long id) {try{ //根據 ID 查詢數據庫 }catch(SQLException e){ //利用非檢測異常封裝檢測異常,降低層次耦合 throw new RuntimeException(SQLErrorCode, e); }finally{ //關閉連接,清理資源 } }
四 不要忽略異常
public void retrieveObjectById(Long id){ try{ //..some code that throws SQLException}catch(SQLException ex){ /** *了解的人都知道,這裏的異常打印毫無意義,僅僅是將錯誤堆棧輸出到控制臺。 * 而在 Production 環境中,需要將錯誤堆棧輸出到日誌。 * 而且這裏 catch 處理之後程序繼續執行,會導致進一步的問題*/ ex.printStacktrace(); } }
異常處理只是將異常輸出到控制臺,沒有任何意義。而且這裏出現了異常並沒有中斷程序,進而調用代碼繼續執行,導致更多的異常。
public void retrieveObjectById(Long id){ try{ //..some code that throws SQLException } catch(SQLException ex){ throw new RuntimeException(“Exception in retieveObjectById”, ex); } finally{ //clean up resultset, statement, connection etc } }
五 不要將異常包含在循環語句中
異常處理占用系統資源
for(int i=0; i<100; i++){ try{ }catch(XXXException e){ //…. } }
六 不要用Exception捕獲所有潛在異常
這個不用贅述了,Exception太籠統,應該捕獲具體的異常。
七 不要多層次打印相同異常
同一段異常會被打印 2 次。如果層次再復雜一點,不去考慮打印日誌消耗的系統性能,僅僅在異常日誌中去定位異常具體的問題已經夠頭疼的了。
其實打印日誌只需要在代碼的最外層捕捉打印就可以了,異常打印也可以寫成 AOP,織入到框架的最外層。
八 異常包含的信息要能充分的定位問題
九 要多考慮可能的潛在異常,在代碼中考慮異常
十 finally中做資源清理等相關工作
十一 請確保在Javadoc中添加一個@throws 聲明,並描述可能導致的異常情況。
十二 異常如果有繼關系
具體的異常卸載前面,抽象的在後面。
十二 包裝異常
有時最好捕獲一個標準異常並將其封裝到一個定制的異常中。此類異常的典型例子是應用程序或框架特定的業務異常。這允許你添加額外的信息,並且也可以為異常類實現一個特殊的處理。
public void wrapException(String input) throws MyBusinessException { try { // do something } catch (NumberFormatException e) { throw new MyBusinessException("A message that describes the error.", e); } }
Java 異常處理的誤區和經驗總結