Java 異常本質上是 繼承自 Throwable 的物件,封裝了錯誤資訊 (訊息、堆疊軌跡、原因鏈)。JVM 偵測到異常狀態時建立異常物件並拋出,若無捕獲邏輯則沿呼叫棧向上傳播,最終終止執行緒。
Throwable
├── Error (嚴重錯誤、JVM 層面、通常不可恢復)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── NoClassDefFoundError
└── Exception (程式邏輯/環境導致、可捕獲處理)
├── RuntimeException (非受檢異常、編譯器不強制捕獲)
│ ├── NullPointerException
│ ├── ClassCastException
│ ├── IllegalArgumentException
│ ├── ArithmeticException
│ ├── ArrayIndexOutOfBoundsException
│ ├── NumberFormatException
│ └── ...
└── IOException 等受檢異常 (編譯器強制 try-catch 或 throws)
├── FileNotFoundException
├── ClassNotFoundException
├── SQLException
└── ...
try {
// 可能拋異常的代碼
} catch (SpecificException e) {
// 處理特定異常
} catch (Exception e) {
// 兜底處理
} finally {
// 必定執行 (除非 System.exit / JVM crash)
// 資源關閉、鎖釋放、清理工作
}
public static int test() {
int i = 10;
try {
return i; // 建立臨時變量暫存 10
} finally {
i = i + 2; // 修改區域變量 i,不影響臨時變量
}
}
// 返回 10,而非 12!
原理:return 時先將值存入操作棧臨時槽,再執行 finally。基本型別為值傳遞,finally 修改的是區域變數副本。
static class Data { int value = 10; }
public static Data testRef() {
Data d = new Data();
try {
return d; // 臨時槽存儲引用
} finally {
d.value = 15; // 修改物件內部狀態,通過引用可見
}
}
// 返回的 Data 物件 value = 15
結論:基本型別/包裝類型/String (不可變) 在 finally 中修改不影響返回值;可變物件修改內部狀態會影響返回結果。
RuntimeException (業務邏輯錯誤) 或 Exception (需呼叫者感知處理)try-with-resources 自動關閉 AutoCloseable 資源throw new BizException("msg", e)catch (Exception e) { } 絕對禁止,至少記錄日誌