天天看點

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(, ));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
           

運作結果:

java.lang.ArithmeticException: / by zero
    at MyMath.div(Test.java:)
    at Test.main(Test.java:)
           

注意: 在調用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(, ));
    }
}
           

運作結果:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at MyMath.div(Test.java:)
    at Test.main(Test.java:)
           

這時主方法将異常繼續向上抛,交給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:)
           

小結: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 = ;
        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(, ));
        } 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 = ;
        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(, ));
        } 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 = ;
        // 假設經過了若幹操作
        assert x ==  : "x的内容不是30";
        System.out.println(x);
    }
}
           

預設情況下,Java之中的斷言,不會在正常執行的代碼中出現,如果要想啟用斷言,則應該增加-ea選項:

java -ea Test
           

運作結果:

Exception in thread "main" java.lang.AssertionError: x的内容不是
        at Test.main(Test.java:)
           

六、自定義異常

在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:)