首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 異常處理六大陋習大公開:你中了幾個?

     編輯:Java 相關知識

挑戰:找出下列代碼的六個問題

1 OutputStreamWriter out = ...
2 java.sql.Connection conn = ...
3 try { // ⑸
4   Statement stat = conn.createStatement();
5   ResultSet rs = stat.executeQuery("select uid, name from user");
6   while (rs.next()) {
7     out.println("ID:" + rs.getString("uid") // ⑹
8       + ",姓名:" + rs.getString("name"));
9   }
10  conn.close(); // ⑶
11  out.close();
12 } catch (Exception ex) { // ⑵
13   ex.printStackTrace(); // ⑴,⑷
14 }

至少能找出兩個算合格,六個全中才算精通。以下逐一剖析。

反例一:吞沒異常

位置:第 12-14 行。捕獲異常僅列印堆疊追蹤,不做任何實質處理。這是 Java 界的「頭號殺手」,頻率與危害極高。printStackTrace() 只適合除錯階段,正式環境必須妥善處理。

四種改正方向:

  1. 就地處理:修正問題、通知相關人員、記錄日誌等。
  2. 重新拋出:無法處理時 throw ex; 讓上層處理。
  3. 轉換異常:將低層異常 (如 SQLException) 包裝為業務異常 (如 ApplicationException),語意更清晰。
  4. 不捕獲:讓異常自然拋出至 JVM 或全域處理器。
結論: 捕獲即責任,絕不可捕獲後置之不理。

反例二:捕獲過寬泛的異常

位置:第 12 行 catch (Exception ex)。試圖一網打盡所有異常是誘人陷阱。實際上應針對具體異常:本例中 SQLException (JDBC) 與 IOException (I/O) 處理邏輯截然不同,必須分開捕獲。其他未預期異常應讓其繼續拋出。

結論: 盡可能指定具體異常型別,必要時多寫幾個 catch 區塊,切勿貪圖省事捕獲 Exception。

反例三:資源未釋放

位置:第 3-14 行。異常會打斷正常流程,若發生在 conn.close() 之前,連線與輸出流將洩漏。Java 提供 finally 保證清理碼必執行。

結論: 所有資源 (檔案、Socket、JDBC 連線) 必須在 finally 中正確釋放,且 finally 內部避免再拋出難以處理的異常。

反例四:錯誤資訊不足

位置:第 3-18 行。迴圈中段拋出異常時,堆疊追蹤僅顯示類別/方法,無法知曉具體是哪筆資料、哪個欄位導致錯誤。應補充上下文資訊 (當前處理的 ID、SQL 語句等),並整理堆疊追蹤為易讀格式。

結論: 異常處理模組需提供足夠診斷資訊:類別、方法、關鍵狀態變數、易讀的錯誤描述。

反例五:try 區塊過大

位置:第 3-14 行。將大量代碼塞進單一 try 如同旅行將所有物品塞進一個大箱子,出錯時難以定位具體語句。應將可能拋出異常的代碼拆分為多個小 try-catch,各自處理對應異常。

結論: 縮小 try 區塊範圍,精準對應異常來源。

反例六:輸出資料不完整

位置:第 6-11 行。迴圈中段異常導致輸出中斷,下游系統收到不完整資料卻無任何警示。資料不完整損害可能超過系統停機。對策:

  • 輸出端寫入「資料不完整」標記
  • 先緩衝全量資料,備妥後一次性輸出
結論: 全面評估異常對執行流程與資料完整性的影響,預留應對機制。

改寫後的標準範例

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);
        }
    }
    if (out != null) {
        try { out.close(); }
        catch (IOException ioex2) {
            System.err(this.getClass().getName() + ".mymethod - 無法關閉輸出檔案: " + ioex2);
        }
    }
}

尾聲

這些不是教條,常識與經驗才是最好老師。無把握時務必加詳盡註釋。別嘲笑這些錯誤——連資深工程師也常因「圖方便」誤入歧途。它們是 Java 世界的惡魔,美麗動人、無孔不入、時刻誘惑。記住:勿以惡小而為之,勿以善小而不為。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved