Java基礎-異常(Exception)處理


                    Java基礎-異常(Exception)處理

                                      作者:尹正傑

版權聲明:原創作品,謝絕轉載!否則將追究法律責任。

 

 

 

一.異常的概述

  什么是異常?Java代碼在運行時期發生的問題就是異常。在Java中,把異常信息封裝成了一個類。當出現了問題時,就會創建異常類對象,並拋出異常相關信息(如異常信息出現的位置,原因等)。

 

二.異常的繼承體系

  在Java中使用Exception類來描述異常。Exception類及其子類是Throwable的一種形式,它指出了合理應用程序想要捕獲的異常條件。查看Java的API文檔我們可以發現Exception有繼承關系,它的父類是Throwable。Throwable是Java語言中所有錯誤或異常的超類。另外,在異常Exception類中,有一個子類要特殊說明一下,RuntimeException子類,RuntimeException及其它的子類只能在Java程序運行過程中出現。

  我們再來觀察Throwable類,能夠發現與異常Exception平級的有一個Error,它是Throwable的子類,它用來表示Java程序中可能會產生的嚴重錯誤。解決辦法只有一個,修改代碼避免Error錯誤的產生。下面是一個Error異常的案例:

  綜上所述,異常繼承體系可以大致做以下簡要分類,此處並未列出全部的異常,請以Java的API文檔為標准,下圖只是為了方便記憶:

三.異常對象的產生原因和處理方式

  我們看見上面的代碼是有異常拋出的,那么異常究竟是怎么拋出的呢?其實他大致分為以下幾個步驟:

1>.JVM檢測到異常

  通過上面的學習,我們知道異常的祖宗其實就是Throwable類,在這個類下面很多個子類已經提前定義好了。在代碼運行的時候,JVM是完全有能力檢測到出現的異常信息(比如:ArrayIndexOutOfBoundsException)。

2>.JVM創建異常對象

  當JVM虛擬機檢測到異常后,首先會創建異常對象(比如:new  java.lang.ArrayIndexOutOfBoundsException: 5)。

3>.將異常拋給方的調用者

  當創建好異常后,首先JVM虛擬機會檢測程序手否對這種類型的異常有相應的處理方式,如果有,則按照業務邏輯執行,如果沒有,就會將異常的對象進行拋出,最終會拋給方法的調用者。

4>.調用者繼續拋出異常

  從上面的代碼中可以看到,getAway方法的調用者是main函數,因此會把異常拋給main方法,JVM虛擬機又會在main方法查找是否有異常處理的方式,如果沒有對數組越界異常進行處理就將異常對象(java.lang.ArrayIndexOutOfBoundsException: 5)繼續向上拋出,也就是main方法的調用者。而main方法運行在棧內存中,實際上是拋給了JVM虛擬機啦。

5>.JVM虛擬機收到異常后的事情

  其實JVM虛擬機(最終異常的處理者)收到異常后,做了兩件事情:

    a>.將異常信息的內容輸出,讓程序員進行排錯;

    b>.殺死拋出異常的進程(也就是結束main方法);

 

四.方法內部拋出對象關鍵字(throw

  在編寫程序時,我們必須要考慮程序出現問題的情況。比如,在定義方法時,方法需要接受參數。那么,當調用方法使用接受到的參數時,首選需要先對參數數據進行合法判斷,數據若不合法,就應該告訴調用者,傳遞合法的數據進來。這時需要使用拋出異常的方式來告訴調用者。在Java中,提供了一個throw關鍵字,它用來拋出一個指定的異常對象。那么,拋出一個異常具體如何操作呢?

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     public static void main(String[] args){
 9         int[] arr = null;
10 //        int[] arr1 = {};
11         int i = getArray(arr);
12         System.out.println(i);
13     }
14     
15     //對數組的最后索引*2,返回
16     public static int getArray(int[] arr){
17         //對方法參數進行合法性的判斷,進行判斷是不是null
18         if(arr == null){
19             //通過關鍵字throw拋出異常的形式,告訴調用者。
20             throw new RuntimeException("傳遞的數組不存在");
21         }
22         
23         
24         //對數組進行判斷,判斷數組中是否儲存在元素。
25         if(arr.length == 0){
26             //以拋出異常的形式,告訴調用者,數組中沒有元素
27             throw new RuntimeException("傳遞的是空數組");
28         }else{
29             int i = arr[arr.length-1];
30             return i*2;
31         }    
32     }
33 }
34 
35 
36 /*
37 以上代碼執行結果如下:
38 Exception in thread "main" java.lang.RuntimeException: 傳遞的數組不存在
39         at ExceptionDemo.getArray(ExceptionDemo.java:20)
40         at ExceptionDemo.main(ExceptionDemo.java:11)
41 */
42     
43     
44     

 

五.異常方法聲明關鍵字(throws)

  throws用於在方法的聲明上,標明此方法可能出現異常的類型,讓調用者自己處理。換句話說,調用了一個拋出異常的方法,調用者就必須處理,若不處理,就會編譯失敗。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     //main方法將異常拋給了JVM虛擬機。
 9     public static void main(String[] args) throws Exception{
10         // int[] arr1 = null;
11         int[] arr2 = {};
12         int i = getArray(arr2);
13         System.out.println(i);
14     }
15     
16     //對數組的最后索引*2,通過throws關鍵字聲明拋出的異常,調用者必須處理,否則編譯失敗!
17     public static int getArray(int[] arr) throws Exception{
18         //對方法參數進行合法性的判斷,進行判斷是不是null
19         if(arr == null){
20             //通過關鍵字throw拋出異常的形式,告訴調用者。
21             throw new Exception("傳遞的數組不存在");
22         }
23         
24         
25         //對數組進行判斷,判斷數組中是否儲存在元素。
26         if(arr.length == 0){
27             //以拋出異常的形式,告訴調用者,數組中沒有元素
28             throw new Exception("傳遞的是空數組");
29         }else{
30             int i = arr[arr.length-1];
31             return i*2;
32         }    
33     }
34 }
35 
36 
37 /*
38 以上代碼執行結果如下:
39 Exception in thread "main" java.lang.Exception: 傳遞的是空數組
40         at ExceptionDemo.getArray(ExceptionDemo.java:28)
41         at ExceptionDemo.main(ExceptionDemo.java:12)
42 */
43     
44     
45     

 

六.Java中的異常處理方式

1>.異常處理格式

1 try{ 2  被檢測的代碼; 3  可能出現異常的代碼; 4 }catch(異常類名變量){ 5  異常的處理方式; 6  循環,判斷,調用方法,變量 7 }finally{ 8  必須要執行的代碼; 9 }

2>.try...異常處理

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     //main方法進行處理異常
 9     public static void main(String[] args){
10         int[] arr = null;
11         try{
12             int i = getArray(arr);
13             System.out.println(i);
14         }catch(NullPointerException e) {
15             System.out.println(e);
16         }
17         System.out.println("Game Over!");
18     }
19     
20     //創建異常對象並拋出
21     public static int getArray(int[] arr) throws NullPointerException{
22         //對方法參數進行合法性的判斷,進行判斷是不是null
23         if(arr == null){ 
24             //手動拋出異常,拋出空指針異常
25             throw new NullPointerException("傳遞的數組不存在");
26         }
27         
28         //對數組的索引進行判斷
29         if(arr.length < 3){
30             //手動拋出異常,拋出數組的索引越界異常
31             throw new ArrayIndexOutOfBoundsException("數組沒有下標為3的索引");
32         }
33         return arr[3]+1;
34     }
35 }
36 
37 
38 
39 
40 
41 
42 /*
43 以上代碼執行結果如下:
44 java.lang.NullPointerException: 傳遞的數組不存在
45 Game Over!
46 
47 
48 */
49     
50     
51     
ExceptionDemo.java 文件內容

 

3>.異常多catch處理

   平級異常,拋出的異常類之間,沒有繼承關系。上下級關系的異常,越高級的父類越應該寫在下面。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     //main方法進行處理異常
 9     public static void main(String[] args){
10         int[] arr = new int[0];
11         try{
12             int i = getArray(arr);
13             System.out.println(i);
14         }catch(NullPointerException e) {
15             System.out.println(e);
16         }catch(ArrayIndexOutOfBoundsException e) {
17             System.out.println(e);
18         }catch(Exception e){        //Exception應該放在最后一個catch,因為它包含上面2種異常。
19             System.out.println(e);
20         }
21         System.out.println("Game Over!");
22     }
23     
24     //可以拋出多個異常
25     public static int getArray(int[] arr) throws NullPointerException,ArrayIndexOutOfBoundsException{
26         //對方法參數進行合法性的判斷,進行判斷是不是null
27         if(arr == null){ 
28             //手動拋出異常,拋出空指針異常
29             throw new NullPointerException("傳遞的數組不存在");
30         }
31         
32         //對數組的索引進行判斷
33         if(arr.length < 3){
34             //手動拋出異常,拋出數組的索引越界異常
35             throw new ArrayIndexOutOfBoundsException("數組沒有下標為3的索引");
36         }
37         return arr[3]+1;
38     }
39 }
40 
41 
42 
43 
44 /*
45 以上代碼執行結果如下:
46 java.lang.ArrayIndexOutOfBoundsException: 數組沒有下標為3的索引
47 Game Over!
48 */

4>.finnal代碼塊

   finally中的代碼塊無論程序是否有異常,程序都必須執行里面的代碼(除非你在來到finally之前就用System.exit(0)退出程序啦!)。它一般用來釋放IO資源,比如關閉文件或者關閉數據庫的鏈接等等。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     //main方法進行處理異常
 9     public static void main(String[] args){
10         int[] arr = new int[0];
11         try {
12             function(100);
13         }catch(Exception e){
14             System.out.println(e);
15         }finally {
16             System.out.println("必須要執行的代碼!");
17         }
18         System.out.println("Game Over!");
19     }
20     
21     //創建異常對象並拋出
22     public static void function(int a)  throws Exception{
23         if(a == 0) {
24             throw new Exception();
25         }else {
26             System.out.println(a);
27         }
28     }
29 }
30 
31 
32 
33 
34 
35 
36 /*
37 以上代碼執行結果如下:
38 100
39 必須要執行的代碼!
40 Game Over!
41 */

5>.運行時期異常的特點

   異常分為編譯異常和運行時異常。

a>.編譯異常

  調用了拋出異常的方法(拋出編譯異常需要在方法上用關鍵字throws聲明異常),不處理的話就會編譯不通過。處理方式有兩種,第一種就是用try語句進行處理,或者是用throws語句丟給調用者去處理。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     //main方法進行處理異常
 9     public static void main(String[] args){
10         int[] arr = new int[0];
11         try {
12             function(100);
13         }catch(Exception e){
14             System.out.println(e);
15         }finally {
16             System.out.println("必須要執行的代碼!");
17         }
18         System.out.println("Game Over!");
19     }
20     
21     //拋出編譯異常需要在方法上用關鍵字throws聲明異常
22     public static void function(int a)  throws Exception{
23             //創建編譯異常
24             throw new Exception();
25     }
26 }
27 
28 
29 
30 
31 /*
32 以上代碼執行結果如下:
33 java.lang.Exception
34 必須要執行的代碼!
35 Game Over!
36 
37 */
編譯異常(Exception)案例展示

b>.運行時期異常

  拋出的異常是RuntimeException類,或者是他的子類。方法內部拋出的異常是運行異常,在方法聲明上,不需要throws語句。不僅如此,運行時異常我們也不需要去用try語句或者throws語句去處理。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 public class ExceptionDemo{
 8     //main方法進行處理異常
 9     public static void main(String[] args){
10         //調用者,不需要處理異常
11         function(100);
12     }
13     //運行時異常可以不用在方法上用關鍵字throws聲明。
14     public static void function(int a){
15             //創建運行時異常
16             throw new RuntimeException();
17     }
18 }
運行時異常(RuntimeException)案例展示

c>.運行異常的設計原因

  運行異常,在編譯的時候不能察覺出來,如果發生了運行異常,程序人員停止程序修改源代碼。運行異常一旦發生,后面的代碼沒有執行的意義。比如我們看下面一段代碼,估計身為老司機的你一眼就看出問題了,但是在編譯的時候就不死活不報錯,一旦你運行就會崩潰。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 
 8 public class ExceptionDemo{
 9     public static void main(String[] args){
10         int[] arr = {1,2,3};
11         function(arr);
12     }
13     
14     public static void function(int[] arr){
15             /*        此處我們對數組的第六個元素進行操作,但是如果傳入的數組長度不到6,
16             *則繼續向下執行代碼就沒有任何意義,程序員應該修改以下的代碼邏輯性!
17             */
18             if(arr[5] > 100) {
19                 arr[5] = arr[5]/10;
20             }else {
21                 arr[5] = arr[5]/3;
22             }
23     }
24 }

d>.運行異常的案例

  定義一個方法,計算一個圓形面積。傳遞參數為負數時可以完成計算,但是違反了真實情況,因此我們可以將傳入的數據進行判斷,如果不符合現實情況就讓程序崩潰掉,讓調用者傳入合法的數據信息,我們舉一個簡單的案例(求圓形的面積,你可以補充求周長來練習):

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 
 8 public class ExceptionDemo{
 9     public static void main(String[] args){
10         //傳入一個負數去求面積,會導致程序崩潰
11         double d = getArea(-1);
12         System.out.printf("圓形的面積是:%f\n",d);
13     }
14     
15     //定義方法,計算圓形的面積
16     public static double getArea(double r){
17         //當傳入的半徑是非正數時,就讓程序崩潰掉!
18         if(r <= 0) {
19             throw new RuntimeException("圓形不存在");
20         }
21         return r*r*Math.PI;
22         
23     }
24 }
25 
26 
27 
28 /*
29 以上代碼執行結果如下:
30 Exception in thread "main" java.lang.RuntimeException: 圓形不存在
31         at ExceptionDemo.getArea(ExceptionDemo.java:19)
32         at ExceptionDemo.main(ExceptionDemo.java:11)
33 
34 */

6>.方法重寫時候異常的處理

   繼承后,在子類重寫父類方法的時候,異常處理結論:

    a>.父類的方法如果拋出異常,子類重寫后可以不拋出異常,也可以不拋出異常,但是,如果子類要拋,拋出的異常不能大於父類的異常(都指的是繼承關系);

    b>.父類的方法沒有異常拋出,子類重寫后也不能拋出異常;

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 
 8 public class ExceptionDemo{
 9     public static void main(String[] args){
10 
11     }
12 }
13 
14 class Father{
15     public void function()throws Exception{
16         
17     }
18 }
19 
20 class Son extends Father{
21     //子類可以拋出異常也可以不拋出異常Exception
22     public void function(){
23         
24     }
25 }
父類拋出異常,子類可以不拋出異常
 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 
 8 public class ExceptionDemo{
 9     public static void main(String[] args){
10 
11     }
12 }
13 
14 class Father{
15     public void function(){
16         
17     }
18 }
19 
20 class Son extends Father{
21     //子類可以拋出異常也可以不拋出異常Exception
22     public void function(){
23         
24     }
25 }
父類不拋出異常,子類就不能拋出異常

 

七.自定義異常

1>.Throwable類常用的方法

  a>.String getMessage()    :對異常信息的詳細描述。
  b>.String toString()      :對異常信息的簡短描述。
  c>.void printStackTrace()   :將異常信息追蹤到標准的錯誤流,也是JVM虛擬機默認調用的方式,因為它的異常信息最詳細。

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 
 8 public class ExceptionDemo{
 9     public static void main(String[] args){
10             try {
11                 function();
12             }catch(Exception e) {
13                 System.out.println(e.getMessage());
14                 System.out.println(e.toString());
15                 e.printStackTrace();            //JVM默認調用的就是這個方法,異常信息最全。
16             }
17             
18     }
19     
20     
21     public static void function() throws Exception{
22         throw new Exception("異常啦!");
23     }
24     
25 }
26 
27 
28 
29 /*
30 以上代碼執行結果如下:
31 異常啦!
32 java.lang.Exception: 異常啦!
33 java.lang.Exception: 異常啦!
34         at ExceptionDemo.function(ExceptionDemo.java:22)
35         at ExceptionDemo.main(ExceptionDemo.java:11)
36 */

2>.自定義異常

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 
 8 //自定義異常類
 9 class MyException extends RuntimeException{
10     
11     MyException(String message){
12         super(message);
13     }
14 }
15 
16 public class ExceptionDemo{
17     public static void main(String[] args){
18         try{
19             test();
20         }catch(MyException e){
21             System.out.println(e.getMessage());
22             //....
23         }
24     }
25     
26     public static void test() throws MyException {
27         throw new MyException("發生自定義異常!");
28     }
29 }
30 
31 
32 
33 /*
34 以上代碼執行結果如下:
35 發生自定義異常!
36 */

 


免責聲明!

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



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