Java 異常的捕獲與處理詳解(二)
技術標籤:Java
一、throws關鍵字
thrwos關鍵字主要是在方法定義上使用的,表示的是此方法之中不進行異常的處理,而交給被呼叫處處理。
例如:
class MyMath {
public int div(int x, int y) throws Exception {
return x / y;
}
}
現在的div()方法之中拋了一個異常出來,表示所有的異常交給被呼叫處進行處理。
class MyMath {
public int div(int x, int y) throws Exception {
return x / y;
}
}
public class Test {
public static void main(String args[]) {
try {
System.out.println(new MyMath().div(10, 0));
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
java.lang.ArithmeticException: / by zero
at MyMath.div(Test. java:3)
at Test.main(Test.java:10)
注意: 在呼叫throws宣告方法的時候,一定要使用異常處理操作進行異常的處理,這屬於強制性的處理。
而主方法本身也屬於方法,那麼在主方法上也可以繼續使用throws進行異常的丟擲:
class MyMath {
public int div(int x, int y) throws Exception {
return x / y;
}
}
public class Test {
public static void main(String args[]) throws Exception {
System.out.println(new MyMath().div(10, 0));
}
}
執行結果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at MyMath.div(Test.java:3)
at Test.main(Test.java:9)
這時主方法將異常繼續向上拋,交給JVM進行異常的處理,也就是採用預設的方式,輸出異常資訊,而後結束程式執行。
注意:在實際開發中,主方法不要加throws,因為程式如果有異常,我們也希望可以正常的結束。
二、throw關鍵字
之前所有異常類物件都是由JVM自動進行例項化操作的,使用者也可以自己手工的丟擲一個異常類例項化物件,就通過throw完成了。
public class Test {
public static void main(String args[]) {
try {
throw new Exception("自定義的異常");
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
java.lang.Exception: 自定義的異常
at Test.main(Test.java:4)
小結:throw和throws的區別?
(1)throw:在方法體內使用,表示人為的丟擲一個異常類物件(這個物件可可以是自己例項化的,也可以是已存在的);
(2)throws:在方法的宣告上使用,表示在此方法中不進行異常的處理,而交給被呼叫處處理。
三、異常處理標準格式
我們有種感覺,finally和throw沒有用處。現要求定義一個div()方法,這個方法有如下的一些要求:
(1)在進行除法操作之前,輸出一行提示資訊;
(2)在除法操作執行完畢後,輸出一行提示資訊;
(3)如果中間產生了異常,則應該交給被呼叫處來進行處理。
class MyMath {
// 出現異常要交給被呼叫處出,使用throws
public int div(int x, int y) throws Exception {
System.out.println("===== 計算開始 =====");
int result = 0;
try {
result = x / y; // 除法計算
} catch (Exception e) {
throw e; // 向上拋
} finally {
System.out.println("===== 計算結束 =====");
}
return result;
}
}
public class Test {
public static void main(String args[]) {
try {
System.out.println(new MyMath().div(10, 0));
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
===== 計算開始 =====
===== 計算結束 =====
java.lang.ArithmeticException: / by zero
at MyMath.div(Test.java:7)
at Test.main(Test.java:20)
以上程式碼也可以做一些簡化:
class MyMath {
// 出現異常要交給被呼叫處出,使用throws
public int div(int x, int y) throws Exception {
System.out.println("===== 計算開始 =====");
int result = 0;
try {
result = x / y; // 除法計算
} finally {
System.out.println("===== 計算結束 =====");
}
return result;
}
}
public class Test {
public static void main(String args[]) {
try {
System.out.println(new MyMath().div(10, 0));
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
===== 計算開始 =====
===== 計算結束 =====
java.lang.ArithmeticException: / by zero
at MyMath.div(Test.java:7)
at Test.main(Test.java:18)
直接使用try…finally,不帶有catch,那麼就連處理的機會都沒有了,所以不建議使用try…finally。標準格式是try…catch、finally、throws、throw一起使用。
四、RuntimeException類
先來觀察一段程式碼
public class Test {
public static void main(String args[]) {
String str = "123";
int num = Integer.parseInt(str);
System.out.println(num * num);
}
}
執行結果:
15129
這個程式就是將一個字串變為了基本資料型別,而後執行乘法操作,但是下面來看一下parseInt()方法定義:
public static int parseInt(String s) throws NumberFormatException
發現這個方法上丟擲了一個NumberFormatException的異常,按照之前所講,如果存在了throws,則必須使用try…catch進行處理,可是現在卻沒有強制要求處理,這是為什麼呢?
來觀察一下NumberFormatException的繼承結構:
java.lang.Object
|- java.lang.Throwable
|- java.lang.Exception
|- java.lang.RuntimeException
|- java.lang.IllegalArgumentException
|- java.lang.NumberFormatException
發現NumberFormatException屬於RuntimeException的子類,而在Java之中明確規定:對於RuntimeException的異常型別,在編譯的時候不會強制性的要求使用者處理,使用者可以根據需要有選擇性的來進行處理,在開發之中,如果沒有處理,那麼出現異常之後將交給JVM預設進行處理。也就是說,RuntimeException的子異常類,可以由使用者根據需要有選擇性的來進行處理。
小結:RuntimeException和Exception的區別?請列舉出幾個常見的RuntimeException.
(1)RuntimeException是Exception的子類;
(2)Exception定義了必須處理的異常,而RuntimeException定義的異常可以選擇性的進行處理。
常見的RuntimeException:
NumberFormatException、ClassCastException、NullPointerException、ArithmeticException、ArrayIndexOutOfBoundsException。
五、assert關鍵字(斷言)
Java中斷言指的是程式執行到某行之後,其結果一定是預期的結果,而在JDK 1.4之後增加了一個assert關鍵字。
兩種語法形式:
(1)形式一:
assert condition;
這裡condition是一個必須為真(true)的表示式。如果表示式的結果為true,那麼斷言為真,並且無任何行動
如果表示式為false,則斷言失敗,則會丟擲一個AssertionError物件。這個AssertionError繼承於Error物件。
(2)形式二:
asser condition:expr;
這裡condition是和上面一樣的,這個冒號後跟的是一個表示式,通常用於斷言失敗後的提示資訊,說白了,它是一個傳到AssertionError建構函式的值,如果斷言失敗,該值被轉化為它對應的字串,並顯示出來。
使用斷言:
public class Test {
public static void main(String args[]) {
int x = 10;
// 假設經過了若干操作
assert x == 30 : "x的內容不是30";
System.out.println(x);
}
}
預設情況下,Java之中的斷言,不會在正常執行的程式碼中出現,如果要想啟用斷言,則應該增加-ea選項:
java -ea Test
執行結果:
Exception in thread "main" java.lang.AssertionError: x的內容不是30
at Test.main(Test.java:5)
六、自定義異常
在Java之中本身已經提供了大量的異常型別,但是在開發之中,這些異常型別還不能滿足於開發的需要。所以在一些系統架構之中往往會提供一些新的異常型別,來表示一些特殊的錯誤,而這種操作就稱為自定義異常類,而要想實現這種自定義異常類,那麼可以讓一個類繼承Exception或RuntimeException。
class MyException extends Exception { // 自定義異常類
public MyException(String msg) {
super(msg);
}
}
public class Test {
public static void main(String args[]) throws Exception {
throw new MyException("自己的異常類");
}
}
執行結果:
Exception in thread "main" MyException: 自己的異常類
at Test.main(Test.java:9)