1. 程式人生 > >Java 異常的捕獲與處理詳解(二)

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)