1. 程式人生 > >關於異常處理的不良習慣和改正方法

關於異常處理的不良習慣和改正方法

關於異常處理的不良習慣

OutputStreamWriter out = ...  
java.sql.Connection conn = ...  
try { // ⑸  
 Statement stat = conn.createStatement();  
 ResultSet rs = stat.executeQuery(  
  "select uid, name from user");  
 while (rs.next())  
 {  
  out.println("ID:" + rs.getString("uid") // ⑹  
   ",姓名:" + rs.getString("name"
));  }  conn.close(); // ⑶  out.close(); } catch(Exception ex) // ⑵ {  ex.printStackTrace(); //⑴,⑷ }

上面的例子共有6個不好的程式設計習慣問題:
1.丟棄異常(15-18行)
這段程式碼捕獲了異常卻不作任何處理,可以算得上Java程式設計中的殺手。如果你看到了這種丟棄(而不是丟擲)異常的情況,可以百分之九十九地肯定程式碼存在問題(在極少數情況下,這段程式碼有存在的理由,但最好加上完整的註釋,以免引起別人誤解)。
有4種該正的選擇:
* 處理異常。針對該異常採取一些行動,例如修正問題、提醒某個人或進行其他一些處理,要根據具體的情形確定應該採取的動作。再次說明,呼叫printStackTrace算不上已經“處理好了異常”。
* 重新丟擲異常。處理異常的程式碼在分析異常之後,認為自己不能處理它,重新丟擲異常也不失為一種選擇。
* 把該異常轉換成另一種異常。大多數情況下,這是指把一個低階的異常轉換成應用級的異常(其含義更容易被使用者瞭解的異常)。
* 不要捕獲異常。
結論一:既然捕獲了異常,就要對它進行適當的處理。不要捕獲異常之後又把它丟棄,不予理睬.

2.不指定具體的異常(15行)
catch語句表示我們預期會出現某種異常,而且希望能夠處理該異常。異常類的作用就是告訴Java編譯器我們想要處理的是哪一種異常。所以一定要指明具體的異常,不要直接用Exception()。
結論二:在catch語句中儘可能指定具體的異常型別,必要時使用多個catch。不要試圖處理所有可能出現的異常。

3.佔用資源不釋放(3-14行)
異常改變了程式正常的執行流程。這個道理雖然簡單,卻常常被人們忽視。如果程式用到了檔案、Socket、JDBC連線之類的資源,即使遇到了異常,也要正確釋放佔用的資源。而上面如果發生了異常,則釋放資源的語句沒有執行到釋放不了,此時應該利用finally關鍵字來執行。當然,編寫finally塊應當多加小心,特別是要注意在finally塊之內丟擲的異常??這是執行清理任務的最後機會,儘量不要再有難以處理的錯誤。
結論三:保證所有資源都被正確釋放。充分運用finally關鍵詞。

4.不說明異常的詳細資訊(3-18行)
printStackTrace的堆疊跟蹤功能顯示出程式執行到當前類的執行流程,但只提供了一些最基本的資訊,未能說明實際導致錯誤的原因,同時也不易解讀。因此,在出現異常時,最好能夠提供一些文字資訊,例如當前正在執行的類、方法和其他狀態資訊,包括以一種更適合閱讀的方式整理和組織printStackTrace提供的資訊。
結論四:在異常處理模組中提供適量的錯誤原因資訊,組織錯誤資訊使其易於理解和閱讀。

5.過於龐大的try塊(3-14行)
把大量的程式碼放在try塊中,當出現問題時很難定位到時哪一個語句導致的異常,正確的做法應該是分離各個可能出現的異常段落並分別捕獲異常。
結論五:儘量減小try塊的體積。

6.輸出資料不完整(7-11行)
不完整的資料是Java程式的隱形殺手。仔細觀察這段程式碼,考慮一下如果迴圈的中間丟擲了異常,會發生什麼事情?使用這些資料的人或裝置將收到一份不完整的(因而也是錯誤的)資料,卻得不到任何有關這份資料是否完整的提示。較為理想的處置辦法是向輸出裝置寫一些資訊,宣告資料的不完整性;另一種可能有效的辦法是,先緩衝要輸出的資料,準備好全部資料之後再一次性輸出。
結論六:全面考慮可能出現的異常以及這些異常對執行流程的影響。若導致資料不完整該如何處理。
改寫後:

OutputStreamWriter out = ...  
java.sql.Connection conn = ...  
try {  
 Statement stat = conn.createStatement();  
 ResultSet rs = stat.executeQuery(  
  "select uid, name from user");  
 while (rs.next())  
 {  
  out.println("ID:" + rs.getString("uid") + ",姓名: " + rs.getString("name"));  
 }  
}  
catch(SQLException sqlex)  
{  
 out.println("警告:資料不完整");  
 throw new ApplicationException("讀取資料時出現SQL錯誤", sqlex);  
}  
catch(IOException ioex)  
{  
 throw new ApplicationException("寫入資料時出現IO錯誤", ioex);  
}  
finally  
{  
 if (conn != null) {  
  try {  
   conn.close();  
  }  
  catch(SQLException sqlex2)  
  {  
   System.err(this.getClass().getName() + ".mymethod - 不能關閉資料庫連線: " + sqlex2.toString());  
  }  
 }  

 if (out != null) {  
  try {  
   out.close();  
  }  
  catch(IOException ioex2)  
  {  
   System.err(this.getClass().getName() + ".mymethod - 不能關閉輸出檔案" + ioex2.toString());  
  }  
 }  
}  

結語:當然具體問題具體對待,以上也只是一部分內容。總之要養成良好的程式設計習慣和程式碼風格,注意細節的處理!