Day26---學習Java第二彈
2021-08-05
Java異常方法
四、自定義異常
在 Java 中你可以自定義異常。如果要自定義異常類,則擴充套件Exception類即可,
因此這樣的自定義異常都屬於檢查異常(checked exception)。如果要自定義非檢查異常,則擴充套件自RuntimeException。
按照國際慣例,自定義的異常應該總是包含如下的建構函式:
一個無參建構函式
一個帶有String引數的建構函式,並傳遞給父類的建構函式。
一個帶有String引數和Throwable引數,並都傳遞給父類建構函式。
一個帶有Throwable 引數的建構函式,並傳遞給父類的建構函式。
下面是IOException類的完整原始碼,可以借鑑。
package java.io; public class IOException extends Exception { static final long serialVersionUID = 7818375828146090155L; public IOException() { super(); } public IOException(String message) { super(message); } public IOException(String message, Throwable cause) { super(message, cause); } public IOException(Throwable cause) { super(cause); } }
finally塊和return、
首先一個不容易理解的事實:在 try塊中即便有return,break,continue等改變執行流的語句,finally也會執行。
finally中的return 會覆蓋 try 或者catch中的返回值。
finally中的return或異常會抑制(消滅)前面try或者catch塊中的異常。
詳細處理情況介紹:
1.try-catch語句
在Java中,異常通過try-catch語句捕獲。其一般語法形式為:
try {
// 可能會發生異常的程式程式碼
} catch (Type1 id1){
// 捕獲並處置try丟擲的異常型別Type1
}
catch (Type2 id2){
//捕獲並處置try丟擲的異常型別Type2
}
關鍵詞try後的一對大括號將一塊可能發生異常的程式碼包起來,稱為監控區域。Java方法在執行過程中出現異常,
則建立異常物件。將異常丟擲監控區域之 外,由Java執行時系統試圖尋找匹配的catch子句以捕獲異常
。若有匹配的catch子句,則執行其異常處理程式碼,try-catch語句結束。
匹配的原則是:如果丟擲的異常物件屬於catch子句的異常類,或者屬於該異常類的子類,則認為生成的異常物件與catch塊捕獲的異常型別相匹配。
例1 捕捉throw語句丟擲的“除數為0”異常。
public class TestException {
public static void main(String[] args) {
int a = 6;
int b = 0;
try { // try監控區域
if (b == 0) throw new ArithmeticException(); // 通過throw語句丟擲異常
System.out.println("a/b的值是:" + a / b);
}
catch (ArithmeticException e) { // catch捕捉異常
System.out.println("程式出現異常,變數b不能為0。");
}
System.out.println("程式正常結束。");
}
}
執行結果:程式出現異常,變數b不能為0。
程式正常結束。
例1 在try監控區域通過if語句進行判斷,當“除數為0”的錯誤條件成立時引發ArithmeticException異常,
建立 ArithmeticException異常物件,並由throw語句將異常拋給Java執行時系統,由系統尋找匹配的異常處理器
catch並執行相應異 常處理程式碼,列印輸出“程式出現異常,變數b不能為0。”try-catch語句結束,繼續程式流程。
事實上,“除數為0”等ArithmeticException,是RuntimException的子類。而執行時異常將由執行時系統自動丟擲,不需要使用throw語句。
例2 捕捉執行時系統自動丟擲“除數為0”引發的ArithmeticException異常。
public static void main(String[] args) {
int a = 6;
int b = 0;
try {
System.out.println("a/b的值是:" + a / b);
} catch (ArithmeticException e) {
System.out.println("程式出現異常,變數b不能為0。");
}
System.out.println("程式正常結束。");
}
}
執行結果:程式出現異常,變數b不能為0。
程式正常結束。
例2 中的語句:
System.out.println("a/b的值是:" + a/b);
在執行中出現“除數為0”錯誤,引發ArithmeticException異常。執行時系統建立異常物件並丟擲監控區域,轉而匹配合適的異常處理器catch,並執行相應的異常處理程式碼。
由於檢查執行時異常的代價遠大於捕捉異常所帶來的益處,執行時異常不可查。Java編譯器允許忽略執行時異常,一個方法可以既不捕捉,也不宣告丟擲執行時異常。
例3 不捕捉、也不宣告丟擲執行
public static void main(String[] args) {
int a, b;
a = 6;
b = 0; // 除數b 的值為0
System.out.println(a / b);
}
執行結果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.TestException.main(TestException.java:8)
例4 程式可能存在除數為0異常和陣列下標越界異常。
public class TestException {
public static void main(String[] args) {
int[] intArray = new int[3];
try {
for (int i = 0; i <= intArray.length; i++) {
intArray[i] = i;
System.out.println("intArray[" + i + "] = " + intArray[i]);
System.out.println("intArray[" + i + "]模 " + (i - 2) + "的值: "
+ intArray[i] % (i - 2));
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("intArray陣列下標越界異常。");
} catch (ArithmeticException e) {
System.out.println("除數為0異常。");
}
System.out.println("程式正常結束。");
}
}
執行結果:
intArray[0] = 0
intArray[0]模 -2的值: 0
intArray[1] = 1
intArray[1]模 -1的值: 0
intArray[2] = 2
除數為0異常。
程式正常結束。
例4 程式可能會出現除數為0異常,還可能會出現陣列下標越界異常。程式執行過程中ArithmeticException異常型別是先行匹配的,因此執行相匹配的catch語句:
catch (ArithmeticException e){
System.out.println("除數為0異常。");
}
需要注意的是,一旦某個catch捕獲到匹配的異常型別,將進入異常處理程式碼。一經處理結束,
就意味著整個try-catch語句結束。其他的catch子句不再有匹配和捕獲異常型別的機會。
Java通過異常類描述異常型別,異常類的層次結構如圖1所示。對於有多個catch子句的異常程式而言,
應該儘量將捕獲底層異常類的catch子 句放在前面,同時儘量將捕獲相對高層的異常類的catch子句放在後面。
否則,捕獲底層異常類的catch子句將可能會被遮蔽。
RuntimeException異常類包括執行時各種常見的異常,ArithmeticException類和ArrayIndexOutOfBoundsException類都是它的子類。
因此,RuntimeException異常類的catch子句應該放在 最後面,否則可能會遮蔽其後的特定異常處理或引起編譯錯誤。