23 例外處理(Exception handling)-1
撰寫Java原始碼、編譯並執行,期間會碰到各種問題,有些屬於程式語法錯誤、程式邏輯錯誤,有些屬於作業系統、硬體錯誤等。這些錯誤有些必須在程式中預作處置,有些則非程式可以控制的。
如果只以Java程式本身的問題來分類,可分為編譯時期的錯誤、執行時期的錯誤及程式邏輯錯誤。
[編譯期錯誤]
在Java編譯時出現(或發現)的錯誤,例如程式碼拼字錯誤、語法錯誤及後述的Checked Exception等屬之。因為這些錯誤造成程式無法完成編譯,當然也就不能執行了。
[執行期錯誤]
顧名思義就是在執行時期出現的錯誤。例如超出陣列範圍、除以0等,造成程式執行中斷。這些錯誤也可能是因為程式邏輯錯誤所導致。
[程式邏輯錯誤]
程式雖然在編譯期及執行期沒有發生錯誤而中斷,但其執行結果並不是預期的結果,就可能是程式設計的邏輯錯誤。
不論是硬體、作業系統及程式問題,這些出現的異常,可分為錯誤(Error)及例外(Exception)。
[23-1異常的分類]
[錯誤(Error)]
為系統本身發生之錯誤等屬之,程式碼置不置入處理方式皆可。
[例外(Exception)]
除數為0及要讀取的檔案不存在等,導致程式無法繼續執行之異常屬之。可分為非受檢例外及受檢例外。
[非受檢例外(Unchecked Exception)]
屬於程式執行時期(Runtime)可能發生各種例外,如除以0,或陣列指標超出範圍等,因這部分屬於程式邏輯部分,可於程式中事前進行檢查防範,可不必置入例外檢查處理程式碼,如要置入亦非不可。如有置入例外處理程式碼,執行時期發生例外時,則依例外處理程式碼處置。編譯程式不檢查非受檢例外(unchecked exception)是否有置入例外處理程式碼。如果程式沒有撰寫例外處理程式碼,即不會捕捉此一異常,會一直往上傳遞至main(),回報至System.err,並會呼叫printStackTrace列印顯示錯誤訊息。
Unchecked Exception:
例外名稱例 |
產生原因 |
ArithmeticException |
運算式產生的例外,例如:除數為0 |
ArrayIndexOutOfBoundsException |
陣列的索引值指定錯誤,例如:超出索引值 |
ArrayStoreException |
指定陣列內容錯誤時產生的錯誤 |
ClassCastException |
類別轉型錯誤 |
IndexOutOfBoundsException |
索引使用時超出範圍,這個類別是ArrayIndexOutOfBoundException的父類別 |
IllegalArgumentException |
呼叫方法時,傳遞錯誤的參數 |
NullPointerException |
使用物件時,該物件的參考值為null |
NumberFormatException |
將字串轉為文字時,產生無法轉換的錯誤 |
SecurityException |
企圖違反安全性的限制 |
[受檢例外(Checked Exception)]
屬於程式執行時期可能發生各種例外,且必須於程式中進行處理,即所謂checked exception,如沒有或找不到要讀取得檔案等。受檢例外錯誤沒有置入例外處理的程式碼,將會發生編譯錯誤,須追加例外處理的程式碼後再編譯。
Checked Exception:
例外名稱例 |
產生原因 |
ClassNotFoundException |
找不到指定的類別,可以發生在使用某個類別的方法,但卻找不到該方法所屬的類別 |
FileNotFoundException |
找不到指定的檔案 |
CloneNotSupportException |
在類別中使用clone()方法,但該類別未實作「Cloneable」介面 |
InterruptedException |
當某個執行緒中斷時,而另一個執行緒試圖使用「interrupt()」方法來中斷已停止執行的執行緒 |
IOException |
檔案、網路…的輸出、入錯誤時產生的例外 |
[23-2內建(標準)例外處理類別]
Java內建例外處理類別體系,皆繼承自Throwable類別,程式可直接引用。
表格列舉:Java系統內建例外處理類別之父子類別關係表
T h r o w a b l e ( 根 類 別 ) |
Error (處不處理皆可) |
VirtualMachineError |
StackOverflowError |
|
OutOfMemoryError |
||||
AssertionError |
||||
LinkageError |
ExceptionInInitializerError |
|||
NoClassDefFoundError |
||||
E x c e p t i o n |
Unchecked Exception (處不處理 皆可) |
RuntimeException |
ArithmeticException |
|
NullPointerException |
||||
IllegalStateException |
||||
IndexOutOfBoundsException |
||||
ClassCastException |
||||
IllegalArgumentException |
||||
Checked Exception (須處理) |
IOException |
EOFException |
||
FileNotFoundException |
||||
ClassNotFoundException |
||||
SQLException |
||||
InterruptedException |
圖例(部分):
[23-3例外處理方式]
[23-3-1使用try/catch/finally區塊]
由拋出例外的方法自行捕捉並處理時使用。
[格式]
try{ 可能會發生例外的程式區塊 }
catch(TypeOneException e1){ 例外1處理區塊 }
catch(TypeTwoException e2){ 例外2處理區塊 }
catch(TypeThreeException e3){ 例外3處理區塊 }
.................
finally{ 無論是否發生例外皆要處理的區塊 }
將可能發生例外的程式碼置於try區塊,而將所有可能的例外處理程式碼,條列於各個catch區塊,理論上可能發生n種例外,就必須要有n個catch區塊對應捕捉並處理。finally則不論發生例外與否,皆會執行的程式區塊,即便finally述句前之try及catch區塊有return敘述,仍會執行完finally述句後才會執行return返回。編譯程式會檢查checked exception有無try/catch/finally區塊,沒有設定時會使程式編譯失敗。但unchecked exception則不須指定,如要指定亦可。
catch之例外類別須由孫類別->子類別->父類別之次序由上往下排列,否則排在後面較下階之例外類別可能執行不到,在編譯階段會發現此一錯誤(compile error)。多個下位例外類別也可只以一個上位類別來總括處理,例如catch只指定「exception」類別,其下ArithmeticException、IndexOutOfBoundsException等皆歸其catch。沒有繼承之直屬關係者,可以任意順序擺放。
[checked exception例] <主方法><未置入try/catch/finally區塊>
import java.io.*;
public class Exceptiontcfm1 {
public static void main(String[] args) {
System.out.println("Opening FileInputStream");
FileInputStream f = new FileInputStream("abc.txt");
//檔案輸出入類別,將在後述章節說明
//假設發生FileNotFoundException
System.out.println("File Opened");
}
}
編譯結果:錯誤
C:\js>javac Exceptiontcfm1.java
Exceptiontcfm1.java:5: error: unreported exception FileNotFoundException; must b
e caught or declared to be thrown
FileInputStream f = new FileInputStream("abc.txt");
^
1 error
*checked exception須置入例外處理程式碼。
備註:
引用Java系統內建類別(分別存放在不同類型之套件中)或第三方類別時,必須使用import敘述,但其中java.lang套件則可省略,java.lang套件包含Math、System、String等。
有輸出入錯誤時,例外處理須使用import java.io.*;
[checked exception例] <主方法> <使用try/catch/finally區塊>
import java.io.*;
public class Exceptiontcfm2{
public static void main(String[] args) {
try {
System.out.println("Opening FileInputStream");
FileInputStream f = new FileInputStream("abc.txt");
//檔案輸出入類別,將在後述章節說明
//假設發生FileNotFoundException
System.out.println("File Opened");
}
catch (FileNotFoundException e1) {
System.out.println("FileNotFoundException caught");
}
catch (Exception e2) {
System.out.println("Exception caught");
}
finally {
System.out.println("Execute finally block");
}
}
}
編譯、執行結果:
C:\js>javac Exceptiontcfm2.java
C:\js>java Exceptiontcfm2
Opening FileInputStream
FileNotFoundException caught
Execute finally block
[checked exception例]<非主方法> <未置入try/catch/finally區塊>
import java.io.*;
public class Exceptiontcfm3 {
public static void main(String[] args) {
Tcfg3 aa = new Tcfg3();
aa.tcfm3();
}
}
class Tcfg3 {
publicvoid tcfm3() {
System.out.println("Opening FileInputStream");
FileInputStream f = new FileInputStream("abc.txt");
//假設發生FileNotFoundException
System.out.println("File Opened");
}
}
編譯結果:錯誤
C:\js>javac Exceptiontcfm3.java
Exceptiontcfm3.java:12: error: unreported exception FileNotFoundException; must
be caught or declared to be thrown
FileInputStream f = new FileInputStream("abc.txt");
^
1 error
*checked exception須置入例外處理程式碼。
[checked exception例] <非主方法> <使用try/catch/finally區塊>
import java.io.*;
public class Exceptiontcfm4 {
public static void main(String[] args) {
Tcfg4 aa = new Tcfg4();
aa.tcfm4();
}
}
class Tcfg4{
void tcfm4() {
try{
System.out.println("Opening FileInputStream");
FileInputStream f = new FileInputStream("abc.txt");
//假設發生FileNotFoundException
System.out.println("File Opened");
}
catch (FileNotFoundException e1) {
System.out.println("FileNotFoundException caught");
}
catch (Exception e2) {
System.out.println("Exception caught");
}
finally {
System.out.println("Execute finally block");
}
}
}
執行結果:
C:\js>javac Exceptiontcfm4.java
C:\js>java Exceptiontcfm4
Opening FileInputStream
FileNotFoundException caught
Execute finally block
[unchecked exception例]<主方法> <未置入try/catch/finally區塊>
由命令列輸入兩個1~3的整數。
import java.io.*;
class MainException1 {
public static void main(String args[]) {
if(args.length <= 1) {
System.out.println("請從命令列輸入兩個1~3的整數");
System.exit(1);
}
int m = 12;
int n = Integer.parseInt(args[0]);
m = m / n;
int[] x = {1,2,3};
int y = x[Integer.parseInt(args[1])-1];
System.out.println("程式結束!");
}
}
編譯、執行結果:
C:\js>javac MainException1.java
C:\js>java MainException1 0 3
Exception in thread "main" java.lang.ArithmeticException: / by zero
at mainException1.main(mainException1.java:10)
C:\js>java mainException1 3 5
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
at mainException1.main(mainException1.java:12)
C:\js>java mainException1 2 2
程式結束!
不使用try/catch/finally區塊,則由JVM進行例外處理。
[unchecked exception例]<主方法> <使用try/catch/finally區塊>
由命令列輸入兩個1~3的整數,
import java.io.*;
class mainException2 {
public static void main(String args[]) {
if(args.length <= 1) {
System.out.println("請從命令列輸入兩個1~3的整數");
System.exit(1); }
try{ int m = 12;
int n = Integer.parseInt(args[0]);
m = m / n;
int[] x = {1,2,3};
int y = x[Integer.parseInt(args[1])-1]; }
catch(ArrayIndexOutOfBoundsException f) {
System.out.println("Out of Range:" + f.getMessage()); }
catch(RuntimeException e) {
System.out.println(e.getMessage()); }
finally{
System.out.println("程式結束!"); }
}
}
編譯、執行結果:
C:\js>javac MainException2.java
C:\js>java MainException2 0 3
/ by zero
程式結束!
C:\js1>java MainException2 3 5
Out of Range:4
程式結束!
C:\js>java mainException2 2 2
程式結束!
*非主方法執行結果會和主方法執行結果一樣。
[23-3-2 throws預告例外]
throws定義於方法名稱之同一列,列出該方法可能出現的異常。目的是告訴要呼叫該方法的方法要處理這些異常,例如以try/catch處理。throws通常定義於非主方法。
import java.io.*;
class ThrowsClass {
void divideArray(int s, int t) throws RuntimeException,
ArrayIndexOutOfBoundsException { //非主方法定義throws
int m = 12;
int n = s;
m = m / n;
int[] x = {1,2,3};
int y = x[t]; } }
class MainException3 {
public static void main(String[] args) { //主方法定義try/catch/finally
if(args.length <= 0) {
System.out.println("請從命令列輸入兩個數字0及1或3及4");
System.exit(1); }
ThrowsClass m = new ThrowsClass();
try{ m.divideArray(Integer.parseInt(args[0]),Integer.parseInt(args[1])); }
catch(ArrayIndexOutOfBoundsException f) {
System.out.println("Out of Range:" + f.getMessage()); }
catch(RuntimeException e) { System.out.println(e.getMessage()); }
finally{ System.out.println("程式結束!"); }
}
}
執行結果:
C:\js>java MainException3 0 1
/ by zero
程式結束!
C:\js1>java MainException3 3 4
Out of Range:4
程式結束!
[23-3-3 throw刻意拋出例外類別]
throw於方法內之try區塊中使用,刻意拋出例外,並由後續之catch區塊捕捉處理。使用throw必須自訂異常訊息。throw可配合throws使用,便於主方法呼叫。
throw並非由實際執行時發生異常才拋出例外,而是程式中在某種條件下刻意拋出之例外。
import java.io.*;
class ThrowsClass2 {
void divideArray(int s, int t) {
int m = 12;
if(s == 0) throw new RuntimeException("除數為0"); //設定例外訊息
int n = s;
m = m / n;
int[] x = {1,2,3};
if (t > 3) throw new ArrayIndexOutOfBoundsException("超出陣列範圍");
int y = x[t]; } }
class MainException4 {
public static void main(String args[]) {
if(args.length <= 0) {
System.out.println("請從命令列輸入兩個數字0及1或3及4");
System.exit(1); }
ThrowsClass2 m = new ThrowsClass2();
try{ m.divideArray(Integer.parseInt(args[0]),Integer.parseInt(args[1])); }
catch(ArrayIndexOutOfBoundsException f) {
System.out.println(f.getMessage()); }
catch(RuntimeException e) { System.out.println(e.getMessage()); }
finally{ System.out.println("程式結束!"); }
}
}
執行結果:
C:\js>java MainException4 0 1
除數為0
程式結束!
C:\js1>java MainException4 3 4
超出陣列範圍
程式結束!
因並非由例外處理機制進行處理,沒自訂訊息時會顯示null,則無法得知例外訊息。
import java.io.*;
class ThrowsClass3 {
void divideArray(int s, int t) {
int m = 12;
if(s == 0) throw new RuntimeException();//不設定例為訊息
int n = s;
m = m / n;
int[] x = {1,2,3};
if (t > 3) throw new ArrayIndexOutOfBoundsException();
int y = x[t]; } }
class MainException5 {
public static void main(String args[]) {
if(args.length <= 0) {
System.out.println("請從命令列輸入兩個數字0及1或3及4");
System.exit(1); }
ThrowsClass3 m = new ThrowsClass3();
try{ m.divideArray(Integer.parseInt(args[0]),Integer.parseInt(args[1])); }
catch(ArrayIndexOutOfBoundsException f) {
System.out.println(f.getMessage()); }
catch(RuntimeException e) { System.out.println(e.getMessage()); }
finally{ System.out.println("程式結束!"); }
}
}
執行結果:
C:\js>java mainException5 0 1
null
程式結束!
C:\js>java mainException5 3 4
null
程式結束!
[23-4認清throws及throw]
throws只是列舉該方法可能發生的例外種類,呼叫該方法時,呼叫者應該要對那些列舉的例外進行處理,如果為主方法時,亦應對那些列舉的例外進行處理,即應要設定有try/catch等。因為如果沒設定有catch,不論有無throws,一律交由JVM處理例外,如下2例:
[設定有throws]
import java.io.*;
public class mainException4 {
public static void main(String args[]) throws ArrayIndexOutOfBoundsException {
if (args.length != 1) {
System.out.println("請輸入一個陣列元素次序值");
System.exit(1);
}
int n = Integer.parseInt(args[0]);
int x[] = {3,6,9,12,15};
System.out.println("陣列元素" + n + " = " + x[n-1] + "!");
System.out.println("程式結束。");
}
}
由JVM(及系統)丟出例外訊息:
C:\js>java mainException4 6
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at mainException4.main(mainException4.java:10)
[沒設定有throws]
import java.io.*;
public class mainException5 {
public static void main(String args[]) {
if (args.length != 1) {
System.out.println("請輸入一個陣列元素次序值");
System.exit(1);
}
int n = Integer.parseInt(args[0]);
int x[] = {3,6,9,12,15};
System.out.println("陣列元素" + n + " = " + x[n-1] + "!");
System.out.println("程式結束。");
}
}
由JVM丟出例外訊息:
C:\js>java mainException5 6
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at mainException5.main(mainException5.java:10)
有某一書籍說有try、finally沒catch時要設定有throws,亦是錯誤的,同上述沒catch時一律由JVM處理。
[沒設定throws]
import java.io.*;
class mainException1_1 {
public static void main(String args[]) {
if(args.length <= 1) {
System.out.println("請從命令列輸入兩個1~3的整數");
System.exit(1);
}
try{
int m = 12;
int n = Integer.parseInt(args[0]);
m = m / n;
int[] x = {1,2,3};
int y = x[Integer.parseInt(args[1])-1];
}
finally{
System.out.println("程式結束!");
}
}
}
由JVM丟出例外訊息:
C:\js>java mainException1_1 0 3
程式結束!
Exception in thread "main" java.lang.ArithmeticException: / by zero
at mainException1_1.main(mainException1_1.java:11)
[設定有throws]
import java.io.*;
class mainException1_2 {
public static void main(String args[]) throws RuntimeException,
ArrayIndexOutOfBoundsException{
if(args.length <= 1) {
System.out.println("請從命令列輸入兩個1~3的整數");
System.exit(1);
}
try{
int m = 12;
int n = Integer.parseInt(args[0]);
m = m / n;
int[] x = {1,2,3};
int y = x[Integer.parseInt(args[1])-1];
}
finally{
System.out.println("程式結束!");
}
}
}
由JVM丟出例外訊息:
C:\js>java mainException1_2 0 3
程式結束!
Exception in thread "main" java.lang.ArithmeticException: / by zero
at mainException1_2.main(mainException1_2.java:12)
[23-5例外處理各類格式整理]
將上述說明以表格方式及簡單例子整理如下:
例外處理各類格式整理:
編號 |
格式 |
說明 |
(1) |
try-catch-finally |
try區塊偵測拋出異常;catch區塊捕捉、處理異常;finally區塊則不論有無異常皆會處理。 |
(2) |
try-catch |
try區塊偵測拋出異常;catch區塊捕捉、處理異常。 |
(3) |
try-finally |
try區塊偵測拋出異常;因無catch區塊,捕捉、處理異常交給上一層(即call方)處理,如一直交到最上層皆無處哩,則由JVM處理,發出錯誤訊息並結束程式;finally區塊則不論有無異常皆會處理。 |
(4) |
throws |
throws則預告這個method可能會發生異常,call方要置入異常處理程序。有無throws並不影響程式編譯及執行,只是作為提醒之用。call方如無置入異常處理程序,則交給上一層或JVM處理。 |
(5) |
throw |
並非由JVM發現之異常,throw可主動刻意拋出異常種類, 拋出之後仍須由異常處理程序處理,沒處理時仍交給上一層或JVM處理。 |
[23-5-1使用try/catch/finally格式]
說明:
*將try/catch/finally置入可能出現異常的地方,即可能發生問題的方法之內。
*try區塊發生問題時,由catch區塊依異常類型加以處理。
*finally區塊是不論發生異常與否皆會執行的程式碼。
*catch及finally區塊執行完畢後,不會回到異常程式碼後方繼續執行。
*finally區塊執行後,會繼續執行其後之程式碼(如果有的話)。
*因在此方法內就已經處理了,不會再將例外提交給上層(例如主方法)或是JVM了。
[主方法例]
import java.io.*;
public class DivideByZeroM1{
public static void main(String[] args){
try{
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束M1-1");
}
catch (ArithmeticException e){
System.out.println(e.getMessage()+"---M1");
}
finally{
System.out.println("程式結束M1-2");
}
System.out.println("程式結束M1-3");
}
}
執行結果:
C:\js>java DivideByZeroM1
/ by zero---M1
程式結束M1-2
程式結束M1-3
[一般方法例]
說明:
*物件呼叫方法如發生異常,經該方法異常處理後,仍會回到呼叫程式碼後之繼續處理。
import java.io.*;
public class DivideByZeroM2{
public static void main(String[] args){
DivideByZeroG2 G2 = new DivideByZeroG2();
G2.methodG2();
System.out.println("程式結束M2");
}
}
class DivideByZeroG2{
public void methodG2(){
try{
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束G2-1");
}
catch (ArithmeticException e){
System.out.println(e.getMessage()+"---G2");
}
finally{
System.out.println("程式結束G2-2");
}
System.out.println("程式結束G2-3");
}
}
執行結果:
C:\js>C:\js>java DivideByZeroM2
/ by zero---G2
程式結束G2-2
程式結束G2-3
程式結束M2
[23-5-2使用try/catch格式]
基本上同try/catch/finally,只是少了finally區塊的處理。
[主方法例]
import java.io.*;
public class DivideByZeroM3{
public static void main(String[] args){
try{
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束M3-1");
}
catch (ArithmeticException e){
System.out.println(e.getMessage()+"---M3");
}
System.out.println("程式結束M3-2");
}
}
執行結果:C:\js>java DivideByZeroM3
/ by zero---M3
程式結束M3-2
[一般方法例]
import java.io.*;
public class DivideByZeroM4{
public static void main(String[] args){
DivideByZeroG4 G4 = new DivideByZeroG4();
G4.methodG4();
System.out.println("程式結束M4");
}
}
class DivideByZeroG4{
public void methodG4(){
try{
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束G4-1");
}
catch (ArithmeticException e){
System.out.println(e.getMessage()+"---G4");
}
System.out.println("程式結束G4-2");
}
}
執行結果:C:\js>java DivideByZeroM4
/ by zero---G4
程式結束G4-2
程式結束M4
[23-5-3使用try/finally格式]
[主方法例]
*沒有catch時,異常會在執行完finally後拋給上一層,本例為JVM顯示訊息。
import java.io.*;
public class DivideByZeroM5{
public static void main(String[] args){
try{
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束M5-1");
}
finally{
System.out.println("程式結束M5-2");
}
System.out.println("程式結束M5-3");
}
}
執行結果:C:\js>java DivideByZeroM5
程式結束M5-2
Exception in thread "main" java.lang.ArithmeticException: / by zero
at DivideByZeroM5.main(DivideByZeroM5.java:6)
[一般方法例]
*沒有catch時,異常會在執行完finally後拋給上一層,但上一層之主方法亦未處理,故再拋給上一層即為JVM顯示訊息。
import java.io.*;
public class DivideByZeroM6{
public static void main(String[] args){
DivideByZeroG6 G6 = new DivideByZeroG6();
G6.methodG6();
System.out.println("程式結束M6");
}
}
class DivideByZeroG6{
public void methodG6(){
try{
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束G6-1");
}
finally{
System.out.println("程式結束G6-2");
}
System.out.println("程式結束G6-3");
}
}
執行結果:C:\js>java DivideByZeroM6
程式結束G6-2
Exception in thread "main" java.lang.ArithmeticException: / by zero
at DivideByZeroG6.methodG6(DivideByZeroM6.java:14)
at DivideByZeroM6.main(DivideByZeroM6.java:5)
[23-5-4 使用throws]
throws句置於方法宣告之方法名及參數之後、{}之前,是預告該方法可能出現之異常,欲呼叫該方法的方法應置入異常處理程式碼,如try/catch/finally。
[主類別內一般方法例]
*都是同一人所編碼,應不須使用throws。
import java.io.*;
public class DivideByZeroM7{
public static void main(String[] args) {
try{
DivideByZeroM7 M7 = new DivideByZeroM7();
M7.methodM7();
}
catch(ArithmeticException e) {
System.out.println(e.getMessage()+"---M7-1");
}
finally{ System.out.println("程式結束M7-2");
}
System.out.println("程式結束M7-3");
}
public void methodM7() throws ArithmeticException {
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束M7-4");
}
}
執行結果:C:\js>java DivideByZeroM7
/ by zero---M7-1
程式結束M7-2
程式結束M7-3
[不同類別的一般方法例]
和上例[主類別內一般方法例]相同用法,為throws主要使用方式。
import java.io.*;
public class DivideByZeroM8{
public static void main(String[] args) {
try{
DivideByZeroG8 G8 = new DivideByZeroG8();
G8.methodG8();
}
catch(ArithmeticException e) {
System.out.println(e.getMessage()+"---M8-1");
}
finally{ System.out.println("程式結束M8-2");
}
System.out.println("程式結束M8-3");
}
}
class DivideByZeroG8{
public void methodG8() throws ArithmeticException {
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束M8-4");
}
}
執行結果:C:\js>java DivideByZeroM8
/ by zero---M8-1
程式結束M8-2
程式結束M8-3
[無異常處理程式碼例]
*不置入try/catch/finally,因屬unchecked exception故可編譯成功,但因無異常處理程式碼,故拋給上層處理,即JVM拋出例外訊息、程式中止。
import java.io.*;
public class DivideByZeroM9{
public static void main(String[] args) {
DivideByZeroG9 G9 = new DivideByZeroG9();
G9.methodG9();
System.out.println("程式結束M9-1");
}
}
class DivideByZeroG9{
public void methodG9() throws ArithmeticException {
int x=10, y=0, z=0;
z=x/y;
System.out.println("程式結束M9-2");
}
}
編譯及執行結果:
C:\js>javac DivideByZeroM9.java
C:\js>java DivideByZeroM9
Exception in thread "main" java.lang.ArithmeticException: / by zero
at DivideByZeroG9.methodG9(DivideByZeroM9.java:13)
at DivideByZeroM9.main(DivideByZeroM9.java:5)
[23-5-5使用throw]
[主類別try(throw)/catch/finally]
於try區塊中使用throw自行拋出例外。
import java.io.*;
public class DivideByZeroM10{
public static void main(String[] args) {
try{ int x=10, y=0, z=0;
if (y==0){
throw new ArithmeticException("除數為0");
}
z=x/y;
System.out.println("程式結束M10-1");
}
catch(ArithmeticException e) {
System.out.println(e.getMessage()+"---M10-2");
}
finally{ System.out.println("程式結束M10-3");
}
System.out.println("程式結束M10-4");
}
}
執行結果:C:\js>java DivideByZeroM10
除數為0---M10-2
程式結束M10-3
程式結束M10-4
[主類別throws-try(throw)/catch/finally]
同上例,但於方法中使用throws預告拋出異常,並無特別用處。
import java.io.*;
public class DivideByZeroM11{
public static void main(String[] args) throws ArithmeticException {
try{ int x=10, y=0, z=0;
if (y==0){
throw new ArithmeticException("除數為0");
}
z=x/y;
System.out.println("程式結束M11-1");
}
catch(ArithmeticException e) {
System.out.println(e.getMessage()+"---M11-2");
}
finally{ System.out.println("程式結束M11-3");
}
System.out.println("程式結束M11-4");
}
}
執行結果:C:\js>java DivideByZeroM11
除數為0---M11-2
程式結束M11-3
程式結束M11-4
[同一類別主方法呼叫一般方法]
import java.io.*;
public class DivideByZeroM12{
public static void main(String[] args) {
try{
DivideByZeroM12 M12 = new DivideByZeroM12();
M12. methodM12();
}
catch(ArithmeticException e){
System.out.println(e.getMessage()+"---M12-1");
}
finally{ System.out.println("程式結束M12-2");
}
System.out.println("程式結束M12-3");
}
void methodM12(){
int x=10, y=0, z=0;
if (y==0)
throw new ArithmeticException("除數為0");
z=x/y;
System.out.println("程式結束M12-4");
}
}
執行結果:C:\js>java DivideByZeroM12
除數為0---M12-1
程式結束M12-2
程式結束M12-3
[不同類別呼叫一般方法]
import java.io.*;
public class DivideByZeroM13{
public static void main(String[] args) { //可放置異常處理
DivideByZeroM13 M13 = new DivideByZeroM13();
M13. methodM13();
}
void methodM13(){ //可放置異常處理
try{
DivideByZeroG13 G13 = new DivideByZeroG13();
G13. methodG13();
}
catch(ArithmeticException e){
System.out.println(e.getMessage()+"---M13-1");
}
finally{ System.out.println("程式結束M13-2");
}
System.out.println("程式結束M13-3");
}
}
class DivideByZeroG13{
void methodG13(){ //可放置異常處理
int x=10, y=0, z=0;
if (y==0)
throw new ArithmeticException("除數為0");
z=x/y;
System.out.println("程式結束G13-4");
}
}
執行結果:C:\js>java DivideByZeroM13
除數為0---M13-1
程式結束M13-2
程式結束M13-3
留言列表