正在載入...
請稍候
封面
示例歌曲名稱
示例藝術家
0:00 / 0:00

播放列表

第九章:例外處理

未分類
4.8k 字

例外處理概述

在 Java 中,例外(Exception)是指在程式執行過程中發生的異常情況。例外處理是一種機制,用來捕捉和處理這些異常情況,確保程式的正常運行。



例外的種類

Java 中的例外主要分為兩類:

  1. 檢查型例外(Checked Exception):在編譯時必須處理的例外,例如 IOExceptionSQLException
  2. 非檢查型例外(Unchecked Exception):在運行時可能發生的例外,例如 NullPointerExceptionArrayIndexOutOfBoundsException



例外處理的基本語法

Java 提供了 try-catch 語句來捕捉和處理例外。基本語法如下:

1
2
3
4
5
6
7
try {
// 可能會發生例外的程式碼
} catch (ExceptionType e) {
// 處理例外的程式碼
} finally {
// 無論是否發生例外都會執行的程式碼
}



使用 try-catch 進行例外處理

以下是一個例子,示範如何使用 try-catch 來處理例外:

1
2
3
4
5
6
7
8
9
10
11
public class ExceptionExample {
public static void main(String[] args) {
try {
int[] numbers = {1, 2, 3};
System.out.println(numbers[3]); // 會拋出 ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("例外類型:" + e.getClass().getName()); // 印出例外類別
System.out.println("錯誤訊息:" + e.getMessage()); // 印出錯誤訊息
}
}
}



最終區塊 finally

finally 區塊用於執行清理工作,如關閉檔案或釋放資源。無論是否發生例外,finally 區塊中的程式碼都會執行。

1
2
3
4
5
6
7
8
9
10
11
public class FinallyExample {
public static void main(String[] args) {
try {
int result = 10 / 0; // 會拋出 ArithmeticException
} catch (ArithmeticException e) {
System.out.println("除以零的錯誤:" + e.getMessage());
} finally {
System.out.println("這個區塊會執行。");
}
}
}



自訂例外

可以透過繼承 Exception 類別來創建自訂例外。以下是一個簡單的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 自訂例外類別,繼承 Exception
class MyException extends Exception {

// 建構子:接收錯誤訊息,傳給父類別 Exception 處理
public MyException(String message) {
super(message); // 將訊息傳給 Exception 類別儲存
}
}

// 測試主程式
public class CustomExceptionExample {
public static void main(String[] args) {
try {
// 主動丟出自訂例外
throw new MyException("這是一個自訂例外!");
} catch (MyException e) {
// 印出例外訊息(來自 Exception 的 getMessage())
System.out.println(e.getMessage()); // 輸出:這是一個自訂例外!
}
}
}

補充展開:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 1. Throwable 類別(Java 原始碼簡化)
public class Throwable implements java.io.Serializable {
private String detailMessage; // 儲存錯誤訊息的欄位

public Throwable(String message) {
detailMessage = message; // 將參數存進來
}

public String getMessage() {
return detailMessage; // 回傳訊息
}
}

// 2. Exception 類別(繼承 Throwable)
public class Exception extends Throwable {
public Exception(String message) {
super(message); // 呼叫 Throwable 的建構子,把 message 傳進去
}
}

// 3. MyException 類別(繼承 Exception)
class MyException extends Exception {
public MyException(String message) {
super(message); // 把訊息再往上傳給 Exception → Throwable
}
}

// 4. 測試主程式
public class CustomExceptionExample {
public static void main(String[] args) {
try {
throw new MyException("這是一個自訂例外!");
} catch (MyException e) {
System.out.println(e.getMessage()); // 輸出:這是一個自訂例外!
}
}
}
1
2
3
4
5
6
7
8
Throwable
├── Exception
│ ├── RuntimeException (運行時異常/非檢查異常)
│ │ ├── ArithmeticException
│ │ ├── ArrayIndexOutOfBoundsException
│ │ └── InputMismatchException
│ └── IOException (檢查異常)
└── Error



例外的傳遞

當一個方法拋出例外時,可以選擇將例外傳遞給呼叫者。透過 throws 關鍵字來實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ThrowExample {
public static void mayThrowException() throws Exception {
throw new Exception("可能發生的例外");
}

public static void main(String[] args) {
try {
mayThrowException();
} catch (Exception e) {
System.out.println("捕捉到例外:" + e.getMessage());
}
}
}

程式流程

  1. try 裡呼叫 mayThrowException()
  2. mayThrowException() 主動丟出一個新的 Exception,訊息是 “可能發生的例外”。
  3. 這個 Exception 立刻「拋出」回呼叫它的地方,也就是 try
  4. 因為 try 內程式丟出 Exception,會直接跳到 catch(Exception e) 來捕捉這個錯誤。
  5. catch 裡用 e.getMessage() 取得這個例外的訊息並印出。



例外處理的建議

  • 儘量使用 try-catch 來處理可能發生的例外。
  • 只捕捉需要處理的例外,不要使用 catch (Exception e) 捕捉所有例外。
  • finally 區塊中釋放資源。
  • 自訂例外時,提供有意義的錯誤訊息。



常見 Exception 與 Error 對照表

類型 說明 / 觸發時機 範例程式碼(簡略)
ArithmeticException 數學錯誤,如除以零 int x = 10 / 0;
ArrayIndexOutOfBoundsException 陣列索引超出範圍 arr[3] = 5;
ClassCastException 錯誤的類型轉型 (Integer)(Object)"abc";
ConcurrentModificationException 遍歷時修改集合 for-each + remove()
EOFException 資料讀取超過結尾(串流) readObject();
FileNotFoundException 檔案不存在 new FileReader("abc.txt");
IllegalArgumentException 傳入非法參數 Thread.sleep(-1);
IllegalStateException 呼叫不合時機的方法 scanner.nextLine(); // close後
IndexOutOfBoundsException 索引越界(泛用) list.get(99);
InputMismatchException 輸入與預期型別不符 scanner.nextInt(); // 輸入abc
InterruptedException 執行緒睡眠或等待時被中斷 Thread.sleep(1000);
IOException I/O 錯誤(讀檔、寫檔) reader.readLine();
NegativeArraySizeException 建立負長度陣列 new int[-3];
NoSuchElementException 無元素可讀取 scanner.nextLine(); // 無輸入
NullPointerException 呼叫 null 物件的方法或欄位 s.length(); // s 是 null
NumberFormatException 字串無法轉成數字 Integer.parseInt("abc");
SecurityException 違反安全管理(例如反射) System.setSecurityManager(...)
StackOverflowError (非 Exception) 遞迴過深導致堆疊爆炸 infiniteRecursion();
StringIndexOutOfBoundsException 字串索引錯誤 "abc".charAt(5);
UnsupportedOperationException 呼叫未支援的方法 List.of(1,2).add(3);
OutOfMemoryError (非 Exception) 記憶體不足 while(true) list.add(new int[999999]);



類型區分補充:

類型分類 說明 範例
Checked Exception 編譯時需處理,用 try-catchthrows IOException, FileNotFoundException
Unchecked Exception 執行時錯誤,編譯器不強制處理 NullPointerException, ArithmeticException
Error 嚴重錯誤,通常不處理 StackOverflowError, OutOfMemoryError