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

Java 異常處理核心機制:拋捕流程、自定義異常、堆棧跟蹤、throws 聲明與最佳實踐

     編輯:Java 綜合教學

Java 異常處理核心機制:拋捕流程、自定義異常、堆棧跟蹤、throws 聲明與最佳實踐

異常機制將「正常業務邏輯」與「錯誤處理邏輯」分離,避免層層 if-else 判斷返回碼。本文深入講解異常拋捕執行流程、自定義異常構造器陷阱、printStackTrace 堆棧原理、throws 聲明規則與實戰建議。

異常拋捕執行流程

異常拋捕流程圖

  1. 方法內拋出異常 (throw new XxxException())。
  2. 2. 當前方法剩餘代碼不再執行,立即回溯調用棧。 3. 尋找最近的匹配 catch 塊 (按聲明順序,子類優先)。 4. 執行 catch 塊處理邏輯。 5. 不返回 拋出點繼續執行,而是執行 catch 後的代碼 (或 finally 後)。
  3. 若無匹配 catch,異常繼續向上拋給調用者,最終到達線程默認處理器 (打印堆棧、終止線程)。

捕獲多異常順序:子類在前,父類在後

try {
    // 可能拋出 NullPointerException、ArrayIndexOutOfBoundsException、IOException
} catch (NullPointerException e) {        // 具體異常優先
    // 處理空指針
} catch (ArrayIndexOutOfBoundsException e) {
    // 處理越界
} catch (IOException e) {
    // 處理 IO
} catch (Exception e) {                   // 兜底
    // 記錄未知異常
}

自定義異常構造器陷阱

// ❌ 錯誤:自定義字段 msg,未調用父類構造器
class MyException extends Exception {
    String msg;
    public MyException(String msg) { this.msg = msg; }
    public void printMsg() { System.out.println(msg); }
}

// ✅ 正確:調用 super(msg) 將信息傳給父類 Throwable 的 detailMessage 字段
class MyException2 extends Exception {
    public MyException2(String msg) { super(msg); }
}

// 測試
try { throw new MyException("msg1"); } catch (MyException e) { System.out.println(e.getMessage()); } // 輸出 null!
try { throw new MyException2("msg2"); } catch (MyException2 e) { System.out.println(e.getMessage()); } // 輸出 msg2

結論:自定義異常必須調用 super(message),否則 getMessage() 返回 null,printStackTrace() 也無詳細信息。

printStackTrace() 堆棧跟蹤原理

JVM 為每個線程維護一個調用棧 (棧幀:方法、行號、局部變量)。異常對象創建時捕獲當前棧快照 (fillInStackTrace()),printStackTrace() 遍歷輸出:

java.lang.NullPointerException
    at com.demo.Test.methodB(Test.java:20)
    at com.demo.Test.methodA(Test.java:15)
    at com.demo.Test.main(Test.java:10)
  • 頂部:異常類型及信息。
  • 每行:at 全類名.方法名(文件名:行號),從拋出點向上到 main/線程入口。
  • Caused by:鏈式異常 (包裹異常 throw new RuntimeException(e))。

throws 聲明規則

  1. 方法拋出受檢異常 (非 RuntimeException 子類),必須 在簽名聲明 throws Exception1, Exception2。
  2. 調用者必須 捕獲 (try-catch) 或繼續 throws 向上拋。
  3. 3. 非受檢異常 (RuntimeException、Error) 無需聲明,但建議文檔註明 (@throws)。 4. 覆寫方法:throws 只能拋出父類方法聲明的異常或其子類 (里氏替換原則)。
public void readFile() throws OpenException, CloseException { // 聲明多個
    if (open() == -1) throw new OpenException();
}

public static void main(String[] args) {
    try { readFile(); }
    catch (OpenException e) { e.printStackTrace(); }
    catch (CloseException e) { e.printStackTrace(); }
}

實戰最佳實踐

  1. 異常分類:業務異常 (受檢,需調用者感知處理) vs 系統異常 (非受檢,統一全局處理)。
  2. 包裹而非吞噬:catch (SQLException e) { throw new BizException("DB錯誤", e); } 保留原始堆棧。
  3. finally 清理資源:流、連接、鎖、臨時文件釋放。JDK 7+ try-with-resources 自動關閉 AutoCloseable。
  4. 避免控制流異常:不用異常做正常流程跳轉 (如 break/return 替代)。
  5. 日誌記錄:log.error("操作失敗", e) 而非 e.printStackTrace(),支持異步輸出、結構化字段。
  6. 全局異常處理:Spring @ControllerAdvice + @ExceptionHandler 統一返回錯誤碼、錯誤信息、追蹤 ID。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved