1. 程式人生 > >Java 異常處理的誤區和經驗總結

Java 異常處理的誤區和經驗總結

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 異常處理的誤區和經驗總結