Java 異常的捕獲與處理詳解 (一)


一,異常的產生(Exception)

  異常是程序之中導致程序中斷的一種指令流,異常一旦出現並且沒有進行合理處理的話,那么程序就會中斷執行。

  An exception is a flow of instruction that causes a program to interrupt in a propram. If an exception occurs and is not properly handled, the program is interrupted.

  (1)不產生異常的程序: the program without any exceptions 

1 public class Test {
2     public static void main(String args[]) {
3         System.out.println("1、除法計算開始。");
4         int result = 10 / 2;
5         System.out.println("2、除法計算結果:" + result);
6         System.out.println("3、除法計算結束。");
7     }
8 }

  運行結果:result of operation

1 1、除法計算開始。
2 2、除法計算結果:5
3 3、除法計算結束。

  (2)產生異常的程序, the program with an exception

1 public class Test {
2     public static void main(String args[]) {
3         System.out.println("1、除法計算開始。");
4         int result = 10 / 0; // 會出現錯誤
5         System.out.println("2、除法計算結果:" + result);
6         System.out.println("3、除法計算結束。");
7     }
8 }

  運行結果:result of operation

1、除法計算開始。Exception in thread "main" 
java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:4)  

  一旦產生異常,我們發現產生異常的語句以及以后的語句將不再執行,默認情況下是進行異常信息輸出,而后自動結束程序的執行。

  Once an exception is generated, we find that the statement that produced the exception and the subsequent statement will no longer be executed, by default the exception information output, and then the execution of the automatic termination program.

  現在我們要做是:即使異常出現了我們也要讓程序正確地執行完畢。

二,異常處理

  如果希望程序出現異常之后程序依然可以正常的完成的話,那么就可以使用如下的格式進行異常的處理:

 

1 try {
2          可能出現異常的語句 ;
3 } [ catch (異常類型 異常對象) {
4          處理異常 ;
5 } catch (異常類型 異常對象) {
6          處理異常 ;
7 } ... ] [finally {
8          不管是否出現異常,都執行此代碼 ;
9 }]

 

  現在,使用以上的操作處理異常處理前面除法於是出現的異常:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法計算開始。");
 4         try {
 5             int result = 10 / 0; // 異常
 6             System.out.println("2、除法計算結果:" + result); // 之前語句有異常,此語句不再執行
 7         } catch (ArithmeticException e) {
 8             System.out.println(e); // 異常處理:輸出錯誤信息,java.lang.ArithmeticException:/ by zero
 9         }
10         System.out.println("3、除法計算結束。");
11     }
12 }

  運行結果:

1 1、除法計算開始。
2 java.lang.ArithmeticException: / by zero
3 3、除法計算結束。

  可以發現,加入了異常處理之后,程序中即使有了異常,程序也可以正常的執行完畢,但是異常處理時的錯誤輸出信息和之前相比,出錯的信息不明確了,那么為了讓錯誤的信息更加的完整,一般都會調用printStackTrace()方法進行異常信息的打印,這個方法打印的異常信息是最完整的:

  

public class Test {
    public static void main(String args[]) {
        System.out.println("1、除法計算開始。");
        try {
            int result = 10 / 0; // 異常
            System.out.println("2、除法計算結果:" + result); // 之前語句有異常,此語句不再執行
        } catch (ArithmeticException e) {
            e.printStackTrace(); // 異常處理:輸出錯誤信息
        }
        System.out.println("3、除法計算結束。");
    }
}

  運行結果:

1、除法計算開始。
java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:5)
3、除法計算結束。

  此時發現,打印的信息是很完整的。

  在此處就多說一點,你重復幾次地去執行上面的程序的時候,你會發現以上信息輸出的順序有時候會有變動,例如下面這樣

1 1,除法計算開始
2 3,除法計算結束
3 java.lang.ArithmeticException: / by zero
4     at com.nokia.test1.exception_1.main(exception_1.java:10)

  個人理解是:當程序調用 e.printStackTrace(); 方法的時候,它也在繼續往下執行,這時候應該是兩個進程在執行着。(如有錯誤歡迎指正!!!

 

  除了try…catch格式處理異常外,還可以使用try…catch..finally:

public class Test {
    public static void main(String args[]) {
        System.out.println("1、除法計算開始。");
        try {
            int result = 10 / 1;
            System.out.println("2、除法計算結果:" + result);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("不管是否出現異常都執行");
        }
        System.out.println("3、除法計算結束。");
    }
}

  運行結果:

1 1、除法計算開始。
2 2、除法計算結果:10
3 不管是否出現異常都執行
4 3、除法計算結束。

  但是,對於之前的程序又有了問題:現在執行數學計算的兩個參數,都是由程序默認提供,那么如果說現在兩個計算的參數通過初始化參數傳遞呢?

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法計算開始。");
 4         try {
 5             int x = Integer.parseInt(args[0]); // 接收參數
 6             int y = Integer.parseInt(args[1]); // 接收參數
 7             int result = x / y;
 8             System.out.println("2、除法計算結果:" + result);
 9         } catch (ArithmeticException e) {
10             e.printStackTrace();
11         } finally {
12             System.out.println("不管是否出現異常都執行");
13         }
14         System.out.println("3、除法計算結束。");
15     }
16 }

  這個時候,數據由外部傳送,那么就有可能出現以下幾類問題: 
  (1)執行時不輸入參數(java TestDemo),ArrayIndexOutOfBoundsException,未處理; 
  (2)輸入的參數不是數字(java TestDemo a b),NumberFormatException,未處理; 
  (3)被除數為0(java TestDemo 10 0),ArithmeticException,已處理。 
  可以發現,以上的程序實際上是存在三種異常,而程序之中只能夠處理一種,而對於不能處理的異常,發現程序依然會直接中斷執行。 
  加入多個catch:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法計算開始。");
 4         try {
 5             int x = Integer.parseInt(args[0]);
 6             int y = Integer.parseInt(args[1]);
 7             int result = x / y;
 8             System.out.println("2、除法計算結果:" + result);
 9         } catch (ArithmeticException e) {
10             e.printStackTrace();
11         } catch (ArrayIndexOutOfBoundsException e) {
12             e.printStackTrace();
13         } catch (NumberFormatException e) {
14             e.printStackTrace();
15         } finally {
16             System.out.println("不管是否出現異常都執行");
17         }
18         System.out.println("3、除法計算結束。");
19     }
20 }

  現在,程序比之前更健壯了。

 三,異常處理流程

   以上已經完成了異常的基本處理,但是所有的異常都想之前那樣一條條判斷似乎是不可能完成的一件事,因為日后肯定會接觸到一些不常見的異常信息,那么下面就首先研究一下JVM異常的處理流程和結構。

  先查看兩個異常類的繼承結構:

  (1)ArithmeticException:

1 java.lang.Object
2     |- java.lang.Throwable
3          |- java.lang.Exception
4               |- java.lang.RuntimeException
5                  |- java.lang.ArithmeticException

  (2)ArrayIndexOutOfBoundsException:

1 java.lang.Object
2    |- java.lang.Throwable
3       |- java.lang.Exception
4          |- java.lang.RuntimeException
5              |- java.lang.IndexOutOfBoundsException
6                 |-java.lang.ArrayIndexOutOfBoundsException

 

   可以發現,所有的異常類型最高的繼承類是Throwable,Throwable下有兩個子類: 
  (1)Error:指的是JVM錯誤,這個時候的程序並沒有執行,無法處理; 
  (2)Exception:指的是程序之中出現的錯誤信息,可以進行異常處理。

通過繼承關系可以發現,在進行日后異常處理的時候是以Exception為主,並且可以形成以下的異常處理流程:

  

  (1)如果程序中產生了異常,那么JVM根據異常的類型,實例化一個指定異常類的對象;

  (2)如果這時程序中沒有任何的異常處理操作,則這個異常類的實例化對象將交給JVM進行處理,而JVM的默認處理方式就是進行異常信息的輸出,而后中斷程序執行;

  (3)如果程序中存在了異常處理,則會由try語句捕獲產生的異常類對象;

  (4)與try之后的每一個catch進行匹配,如果匹配成功,則使用指定的catch進行處理,如果沒有匹配成功,則向后面的catch繼續匹配,如果沒有任何的catch匹配成功,則這個時候將交給JVM執行默認處理;

  (5)不管是否有異常都會執行finally程序,如果此時沒有異常,執行完finally,則會繼續執行程序之中的其他代碼,如果此時有異常沒有能夠處理(沒有一個catch可以滿足),那么也會執行finally,但是執行完finally之后,將默認交給JVM進行異常的信息輸出,並且程序中斷。

  通過以上的分析可以發現,實際上catch捕獲異常類型的操作,就和方法接收參數是一樣的,那么按照之前所學習過的對象多態性來講,所有的異常類都是Exception的子類,那么這個時候,實際上所有的異常都可以使用Exception進行接收:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法計算開始。");
 4         try {
 5             int x = Integer.parseInt(args[0]);
 6             int y = Integer.parseInt(args[1]);
 7             int result = x / y;
 8             System.out.println("2、除法計算結果:" + result);
 9         } catch (Exception e) {
10             e.printStackTrace();
11         } finally {
12             System.out.println("不管是否出現異常都執行");
13         }
14         System.out.println("3、除法計算結束。");
15     }
16 }

 這時應該可以感受到異常處理所帶來的好處了。但是這種操作也存在一種問題:如果在一些異常處理要求嚴格的項目之中,異常必須分別處理,如果現在異常的處理要求不是很嚴格,直接編寫Exception就足夠了。

未完待續。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM