Java中的異常報告和處理機制 && Java中的異常棧軌跡和異常鏈

參考文獻:html

https://www.cnblogs.com/zhangdaicong/p/6127984.htmljava

 

爲了應對運行期間可能出現的錯誤,提升程序的的穩健性,Java中定義了強大的異常處理機制。程序員

Java的異常機制在加強程序穩健性的同時(圍繞異常聲明,在編譯期間就具備嚴格的異常制度),加強了業務代碼的邏輯性和連貫性(經過try-catch,避免了C等語言下的業務邏輯代碼和異常檢測代碼嚴重混合)。數組

異常聲明:Java要求能拋出異常的方法必須加上異常聲明(該些異常未被處理,且非Java中定義的標準異常)。dom

Example:函數

1 package demo;
 2 import static net.mindview.util.Print.*;
 3 
 4 public class TestException {
 5     TestException(int i) throws ExceptionA,ExceptionB{
 6         switch(i)
 7         {
 8         case 1 : throw new ExceptionA();
 9         case 2 : throw new ExceptionB();
10         default : {int a[]={0,}; a[1]=1;};
11         }
12     }
13 }
14 class ExceptionA extends Exception{};
15 class ExceptionB extends Exception{};
1 package demo;
 2 
 3 import net.mindview.*;
 4 import net.mindview.util.PackageTest;
 5 
 6 import java.util.Arrays;
 7 import java.util.Random;
 8 
 9 import static net.mindview.util.Print.*;
10 
11 import static net.mindview.util.Range.*;
12 
13 import trypackage.*;
14 
15 public class printtry {
16 
17     /**
18      * @param args
19      */
20     public static void main(String[] args) {
21         for(int i=0;i<=3;i++)
22         {
23             try{
24                 print("Test:"+Integer.toString(i));
25                 TestException testException=new TestException(i);
26                 }
27                 catch(ExceptionA e)
28                 {
29                     print("Catch the exception from:A cathcing block");
30                     e.printStackTrace();
31                 }
32                 catch(ExceptionB e)
33                 {
34                     print("Catch the exception from:B catching block");
35                     e.printStackTrace();
36                 }
37                 catch(Exception e)
38                 {
39                     print("Catch the exception from:others catching block ");
40                     e.printStackTrace();
41     
42                 }
43                 finally
44                 {
45                     print("The finally block must be executed!");
46                 }
47         }
48         
49 
50     }
51 
52 }

運行結果:spa

從Example 中能夠發現:設計

一、異常聲明極其重要性code

異常聲明:即用戶必須將函數可能拋出的全部自定義異常(即非標準異常),添加到函數聲明中。htm

TestException(int i) throws ExceptionA,ExceptionB 方法(爲TestException類的構造方法),因爲其函數體中會拋出ExceptionA和ExceptionB兩類用戶自定義的異常,故必須在其函數聲明中添加異常聲明:throws ExceptionA,ExceptionB,不然Java沒法讓該文件編譯經過。

你可能會注意到:default : {int a[]={0,}; a[1]=1;};該語句會產生明顯的數組訪問下標越界異常,可是卻未將其添加到函數的異常聲明中。這是由於此異常屬於Java中自定義的非標準異常,其會自動的被逐層上報給main()函數(若上報的過程當中未被try-catch處理)。

Java爲何要求異常聲明?

這正是Java相比於C等語言的獨特之處,Java的異常聲明給編譯器提供了一個很是重要的信息,即:該方法會產生哪些異常

一旦編譯器能夠肯定方法體會產生的異常,那麼當該方法被置於try塊中時,編譯器就會強制的要求全部的異常都要能被catch處理

若以上的的程序改成:

+ View Code

該程序將沒法被編譯經過,由於編譯器經過方法的異常聲明TestException(int i) throws ExceptionA,ExceptionB已經得知:TestException會拋出ExceptionA和ExceptionB兩類異常,而此處的catch模塊只給出了catch(ExceptionA e),即ExceptionB被沒有被處理。這也正是Java竭力設計出異常機制,以保證程序健壯性的緣由。

注意:Java此處只是提供了一種檢查機制(提醒機制),至於異常可否被處理或者可否被妥善的處理,徹底由程序員所決定。程序員也許爲了編譯讓的經過會寫出:

+ View Code

此處雖然catch了ExceptionB,而且保證了程序可以順利的編譯經過,可是程序員卻對此異常什麼也沒作!

看上去好像並無起處處理異常的做用? 確實如此,程序員未給出任何的處理辦法,一旦相應的異常產生,無應對措施!

可是這徹底是由使用該方法的程序員所形成的,Java已經經過本身的檢查機制提醒了程序員須要的異常處理,已經起到了加強程序健壯性的做用!

起碼讓程序知道了這裏有一個必須處理的異常,至因而否處理,如何處理,已經不是編譯可以控制的事情。

 

二、異常類的繼承和處理機制。

下一個程序卻能編譯經過:爲何程序中未給出ExceptionB的catch處理,可是仍然可以編譯經過。

+ View Code

這是由於添加了catch(Exception a)模塊,使得全部的異常都能被catch。這是爲何呢?

由於Exception是全部異常類的基類,包括Java中的常規異常:

+ View Code

catch模塊會對try中捕獲到的異常對象(一次只可能產生一個異常對象),依次的進行匹配,一旦匹配成功即轉入catch塊中進行相應的處理。

在匹配的過程當中,若是catch聲明的爲基類異常對象,那麼其導出類的異常對象是能夠被其正常捕獲的,即自動實現了向上的轉型

 

Exception類爲全部異常類的基類,故編譯器認爲ExceptionB對象能被catch,因此沒有產生編譯錯誤。

重要: catch(Exception e){}又被稱爲捕獲所有異常對象,經常用於放在最後一個catch中,保證全部意料以外的異常對象都能被捕獲。

+ View Code

catch(Exception e)雖然能捕獲全部異常對象,可是其處理方法卻只能有一種,無針對性,對任何意料以外的異常都要適用。因此其處理方法通常爲將捕獲的異常對象的信息經過e.printStackTrace()方法輸出到控制檯,以提醒程序員何種意料以外的異常發生了。

機制:對於同一個try塊,Java不容許catch(基類)出如今catch(相應導出類)以前,以覆蓋了更好的異常處理方法。

 

(二:)

Java中容許對異常進行再次拋出,以提交給上一層進行處理,最爲明顯的例子爲Java的常規異常。

常規異常:有Java所定義的異常,不須要異常聲明,在未被try-catch的狀況下,會被默認上報到main()方法。

Example:

public class TestException {

    TestException(int i) throws ExceptionA,ExceptionB{

        int a[]={0,}; a[1]=1;

    }

}

當從main()方法中調用TestException類的構造函數的時候,會獲得如下的異常提示,從中能夠看出異常的冒泡機制(這是一個棧信息)。

異常的冒泡上傳機制:當一個異常對象產生了之後,其會按照調用層次(通常是方法的調用層次)進行冒泡,直到被try-catch處理,或上報至main()方法,有編譯器進行提示。

Example:

firstThrow()提示錯誤的緣由爲, firstThrow()的函數聲明中包括了MyException的異常聲明,而secondThrow()中調用了firstThrow()卻未對可能拋出的異常對象提供任何處理方案,這是編譯器所不能容許發生的事情。(這也是爲了保證底層異常對象在冒泡過程當中,能獲得合適的處理和重視!)

注意此截圖中,MyEclipse提供了兩種方式幫助fix這個程序這兩種方式經常使用的異常應對手段

一、本方法不給予處理,將異常上報給上一層。

1 public class TestExceptionChain {
 2     void firstThrow() throws MyException
 3     {
 4         print("Oringinally creat a MyException and throw it out");
 5         throw new MyException();
 6         
 7     }
 8     void secondThrow() throws MyException
 9     {
10         firstThrow();
11     }
12     TestExceptionChain() throws MyException{
13         secondThrow();
14     }
15 }

複製代碼

 

1 public static void main(String[] args) {
 2         try{
 3          
 4             TestExceptionChain testExceptionChain=new TestExceptionChain();
 5         }
 6         catch(MyException e)
 7         {
 8             e.printStackTrace();
 9             print("Catch a my exception!");
10         }
11 
12     }

控制檯的輸出爲:

從異常棧的記錄信息能夠發現,與代碼相對應的異常拋出機制和次序:

firstThrow()產生MyException對象->異常冒泡至調用其的secondThrow()->異常冒泡至調用secondThrow()的TestExceptionChain的構造方法->冒泡至printtry的main()方法。

注意到:異常對象一直被拋出,直至在printtry的mian()方法中被try-catch捕獲!

二、try-catch方式,捕捉上報的異常,然後進行相應處理或拋出另外一異常。

二、1捕獲異常後,進行相應處理。

Example:

1 public class TestExceptionChain {
 2     void firstThrow() throws MyException
 3     {
 4         print("Oringinally creat a MyException and throw it out");
 5         throw new MyException();
 6     }
 7     void secondThrow()
 8     {
 9         try
10         {
11         firstThrow();
12         }
13         catch (MyException e)
14         {
15             print("I have just caught a MyExcepton,but i want to do nothing for it");
16             e.printStackTrace();
17         }
18     }
19     TestExceptionChain(){
20         secondThrow();
21     }

從圖中能夠發現,異常在secondThrow() 中被try-catch模塊捕獲,並執行了相應的處理操做,因此其函數聲明中無需添加異常聲明,異常不會被上報

故mian()方法被改寫成了如下的代碼:

1 TestExceptionChain testExceptionChain=new TestExceptionChain();

注意此處異常棧的信息,表示的是異常產生的層次信息,並不是異常信息的上報層次,由於其已經在secondThorow()中被捕獲處理。

2.2 捕獲異常後,拋出另外一個異常。

Example:

1 public class TestExceptionChain {
 2     void firstThrow() throws MyException
 3     {
 4         print("Oringinally creat a MyException and throw it out");
 5         throw new MyException();
 6     }
 7     void secondThrow() throws YouException
 8     {
 9         try
10         {
11         firstThrow();
12         }
13         catch (MyException e)
14         {
15             print("I have just caught a MyExcepton,but i want to create a YouException and throw it out");
16             e.printStackTrace();
17             throw new YouException();
18         }
19     }
20     TestExceptionChain() throws YouException{
21         secondThrow();
22     }
23 }
24 class MyException extends Exception{}
25 class YouException extends Exception{}

從異常棧信息中能夠發現,新拋出的YouException對象是從secondThrow()中開始的。

*Java中還提供了fillInStackTrace()方法,用於對捕獲的異常的棧信息進行重寫。

Example:

1 try{
 2          
 3             TestExceptionChain testExceptionChain=new TestExceptionChain();
 4         }
 5         catch(YouException e)
 6         {
 7             print("Catch a YouException!");
 8             e.fillInStackTrace();
 9             e.printStackTrace();
10             
11         }

 因爲使用了fillInstack()方法,關於YouException的異常信息被重寫,從其被從寫處從新記錄!

相關文章
相關標籤/搜索