第 第 十 十 三 三 章 章 例 例 外 外 處 處 理 理
本章學習目標
了解什麼是例外處理
認識例外類別的繼承架構
認識例外處理的機制
學習如何撰寫例外類別
13.1 例外的基本觀念
在執行程式時,經常發生一些不尋常的狀況。例如:
(1) 要開啟的檔案不存在。
(2) 陣列的索引值超過了陣列容許的範圍。
(3) 使用者輸入錯誤。
Java 把這類不尋常的狀況稱為「例外」(exception)。
13.1.1 為何需要例外處理?
9 易於使用
9 可自行定義例外類別
9 允許我們拋出例外
9 不會拖慢執行速度
13.1.2 簡單的例外範例 app13_1 是個錯誤的程式:
01 // app13_1, 索引值超出範圍 02 public class app13_1 03 {
04 public static void main(String args[]) 05 {
06 int arr[]=new int[5]; // 容許 5 個元素 07 arr[10]=7; // 索引值超出容許範圍 08 System.out.println("end of main() method !!");
09 } 10 }
app13_1 執行時,會產生下列的錯誤訊息:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at app13_1.main(app13_1.java:7)
Java 的預設例外處理機制會依下面的程序做處理:
(1)拋出例外
(2)停止程式執行。
13.1.3 例外的處理
例外處理:加上捕捉例外的程式碼,可針對不同的例外做妥善的處理。
例外處理的語法如下:
try {
// 要檢查的程式敘述;
}
catch(例外類別 變數名稱) {
// 例外發生時的處理敘述;
} finally {
// 一定會執行的程式碼;
}
格式13.1.1 例外處理的語法 try 區塊
catch 區塊
finally 區塊
下圖繪出了例外捕捉的流程圖:
try{} 是否捕 捉到例外 ? try{} 是否捕 捉到例外 ?
執行catch區塊裡 的敘述 執行 catch 區塊
裡的敘述 與catch() 裡 的例外相同 ?
與catch() 裡 的例外相同 ?
true
其它的敘述 其它的敘述 false
false
執行 finally 區塊 裡的敘述 執行 finally 區塊
裡的敘述 true
下面是例外處理的範例:
01 // app13_2,例外的處理 02 public class app13_2 03 {
04 public static void main(String args[]) 05 {
06 try // 檢查這個程式區塊的程式碼 07 {
08 int arr[]=new int[5];
09 arr[10]=7;
10 }
11 catch(ArrayIndexOutOfBoundsException e) 12 {
13 System.out.println("index out of bound!!");
14 }
15 finally // 這個區塊的程式碼一定會執行 16 {
17 System.out.println("this line is always executed!!");
18 }
19 System.out.println("end of main() method!!");
20 } 21 }
如果拋例外,
便執行此區塊 的程式碼 /* app13_2 OUTPUT--- index out of bound!!
this line is always executed!!
end of main() method!!
---*/
如果捕捉到例外,Java 會利用例外類別建立一個類別變數 e:
01 // app13_3, 例外訊息的擷取 02 public class app13_3 03 {
04 public static void main(String args[]) 05 {
06 try 07 {
08 int arr[]=new int[5];
09 arr[10]=7;
10 }
11 catch(ArrayIndexOutOfBoundsException e) 12 {
13 System.out.println("index out of bound!!");
14 System.out.println("Exception="+e); // 顯示例外訊息 15 }
16 System.out.println("end of main() method !!");
17 }
18 } /* app13_3 OUTPUT--- index out of bound!!
Exception=java.lang.ArrayIndexOutOfBoundsException end of main() method !!
---*/
13.1.4 例外處理機制的回顧
下圖繪出了例外處理機制的選擇流程:
例外處理機制
自行撰寫try-catch-filally 區塊來處理例外,
如app13_2, app13_3
交由Java 的預設例外處理機制來處理,
如app13_1
1
2
Throwable Throwable
Error
Error ExceptionException
RuntimeException RuntimeException IOException
IOException
IndexOutOfBoundsException IndexOutOfBoundsException
ArrayIndexOutOfBoundsException ArrayIndexOutOfBoundsException ArithmeticException
ArithmeticException
StringIndexOutOfBoundsException StringIndexOutOfBoundsException
... ...
... ...
... ...
... ...
13.2 例外類別的繼承架構
例外類別可分為兩大類:java.lang.Exception 與 java.lang.Error。
下圖為 Throwable 類別的繼承關係圖:
當例外發生時,catch() 程式區塊會接收由 Throwable 類別的子類別所 產生的物件:
catch( ArrayIndexOutOfBoundsException e ) {
System.out.println("index out of bound!!");
System.out.println("Exception="+e); // 顯示例外訊息 }
只接收由Throwable類別的子類別所產生的物件
使用 try 捕捉一種以上的例外
若要捕捉 ArithmeticException 和 ArrayIndexOutOfBoundsException 兩個例外,可以用如下的語法來撰寫:
01 try 02 {
03 // try 區塊的程式碼 04 }
05 catch(ArrayIndexOutOfBoundsException e) 06 {
07 // 捕捉到 ArrayIndexOutOfBoundsException 例外所執行的程式碼 08 }
09 catch(ArithmeticException e) 10 {
11 // 捕捉到 ArithmeticException 例外所執行的程式碼 12 }
捕捉所有的例外
不論例外類別為何,都想捕捉它的話,則可在 catch() 的括號內填上 Exception 例外:
01 catch(Exception e) 02 {
03 // 捕捉任何例外所執行的程式碼 04 }
13.3 拋出例外
拋出例外有下列兩種方式:
(1) 於程式中拋出例外。
(2) 指定 method 拋出例外。
13.3.1 於程式中拋出例外
於程式中拋出例外時,要用到 throw 這個關鍵字,其語法如下:
throw 由例外類別所產生的物件;
格式13.3.1 例外處理的語法
app13_4 是於程式中拋出例外的範例:
01 // app13_4, 於程式中拋出例外 02 public class app13_4 03 {
04 public static void main(String args[]) 05 {
06 int a=4,b=0;
07 08 try 09 {
10 if(b==0)
11 throw new ArithmeticException(); // 拋出例外 12 else
13 System.out.println(a+"/"+b+"="+a/b); // 若沒有拋出例外,則執行此 行
14 }
15 catch(ArithmeticException e) 16 {
17 System.out.println(e+" throwed");
18 } 19 }
20 } /* app13_4 OUTPUT---
java.lang.ArithmeticException throwed ---*/
app13_5 是讓系統自動拋出例外的驗證:
01 // app13_5, 讓系統自動拋出例外 02 public class app13_5
03 {
04 public static void main(String args[]) 05 {
06 int a=4,b=0;
07 08 try 09 {
10 System.out.println(a+"/"+b+"="+a/b);
11 }
12 catch(ArithmeticException e) 13 {
14 System.out.println(e+" throwed ");
15 } 16 } 17 }
/* app13_5 OUTPUT--- java.lang.ArithmeticException throwed: / by zero throwed ---*/
13.3.2 指定 method 拋出例外
若是要由 method 拋出例外,method 必須以下面的語法來定義:
method 名稱(引數...) throws 例外類別 1,例外類別 2,...
{
// method 內的程式碼 }
格式13.3.2 由method 拋出例外
app13_6 是指定由 method 來拋出例外的範例。
01 // app13_6, 指定 method 拋出例外 02 public class app13_6
03 {
04 public static void aaa(int a,int b) throws ArithmeticException 05 {
06 int c;
07 c=a/b;
08 System.out.println(a+"/"+b+"="+c);
09 } 10
11 public static void main(String args[]) 12 {
13 try 14 {
15 aaa(4,0);
16 }
17 catch(ArithmeticException e) 18 {
19 System.out.println(e+" throwed");
20 } 21 } 22 }
/* app13_6 OUTPUT--- java.lang.ArithmeticException: / by zero throwed ---*/
app13_7 說明了如何從不同類別裡的 method 裡拋出例外:
01 // app13_7, 從不同類別內的 method 拋出例外 02 class Ctest
03 {
04 public static void aaa(int a,int b) throws ArithmeticException 05 {
06 int c=a/b;
07 System.out.println(a+"/"+b+"="+c);
08 } 09 }
10
11 public class app13_7 12 {
13 public static void main(String args[]) 14 {
15 try 16 {
17 Ctest.aaa(4,0);
18 }
19 catch(ArithmeticException e) 20 {
21 System.out.println(e+" throwed");
22 } 23 }
24 } /* app13_7 OUTPUT--- java.lang.ArithmeticException: / by zero throwed ---*/
13.4 自己撰寫例外類別 自行撰寫例外類別的語法如下:
class 例外類別名稱 extends Exception {
// 定義類別裡的各種成員 }
格式13.4.1 撰寫自訂例外類別 的語法
下面的範例說明了如何定義自己的例外類別,以及使用它們:
01 // app13_8, 定義自己的例外類別
02 class CCircleException extends Exception // 定義自己的例外類別 03 {
04 } 05
06 class CCircle // 定義類別 CCircle 07 {
08 private double radius;
09 public void setRadius(double r) throws CCircleException 10 {
11 if(r<0) 12 {
13 throw new CCircleException(); // 拋出例外 14 }
15 else
16 radius=r;
17 }
18 public void show() 19 {
20 System.out.println("area="+3.14*radius*radius);
21 }
由method 拋出例外
22 } 23
24 public class app13_8 25 {
26 public static void main(String args[]) 27 {
28 CCircle cir=new CCircle();
29 try 30 {
31 cir.setRadius(-2.0);
32 }
33 catch(CCircleException e) // 捕捉由 setRadius()拋出的例外 34 {
35 System.out.println(e+" throwed");
36 }
37 cir.show();
38 } 39 }
/* app13_8 OUTPUT--- CCircleException throwed area=0.0
---*/
由 main()拋出例外讓 系統預設的例外處理 機制來處理
13.5 回顧 IOException 例外類別
會拋出 IOException 例外的 method,其例外處理的方式有兩種。
第一種是直接由 main()拋出例外,app3_13 所採用的就是這種機制:
01 // app3_13,由鍵盤輸入字串 02 import java.io.*;
03 public class app3_13 04 {
05 public static void main(String args[]) throws IOException 06 {
.. ...
16 } 17 }
第二種方式是撰寫 try-catch 區塊來捕捉拋出的例外,如下面的範例:
01 // app13_9,撰寫 try-catch 區塊來捕捉 IOException 例外 02 import java.io.*; // 載入 java.io 類別庫裡的所有類別 03 public class app13_9
04 {
05 public static void main(String args[]) 06 {
07 BufferedReader buf;
08 String str;
09
10 buf=new BufferedReader(new InputStreamReader(System.in));
11 try 12 {
13 System.out.print("Input a string: ");
14 str=buf.readLine();
15 System.out.println("string= "+str); // 印出字串 16 }
17 catch(IOException e){}
18 }
19 } /* app13_9 OUTPUT---
Input a string: Hello Java!
string= Hello Java!
---*/