參考文獻: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處理。
若以上的的程序改成:
該程序將沒法被編譯經過,由於編譯器經過方法的異常聲明TestException(int i) throws ExceptionA,ExceptionB已經得知:TestException會拋出ExceptionA和ExceptionB兩類異常,而此處的catch模塊只給出了catch(ExceptionA e),即ExceptionB被沒有被處理。這也正是Java竭力設計出異常機制,以保證程序健壯性的緣由。
注意:Java此處只是提供了一種檢查機制(提醒機制),至於異常可否被處理或者可否被妥善的處理,徹底由程序員所決定。程序員也許爲了編譯讓的經過會寫出:
此處雖然catch了ExceptionB,而且保證了程序可以順利的編譯經過,可是程序員卻對此異常什麼也沒作!
看上去好像並無起處處理異常的做用? 確實如此,程序員未給出任何的處理辦法,一旦相應的異常產生,無應對措施!
可是這徹底是由使用該方法的程序員所形成的,Java已經經過本身的檢查機制提醒了程序員須要的異常處理,已經起到了加強程序健壯性的做用!
起碼讓程序知道了這裏有一個必須處理的異常,至因而否處理,如何處理,已經不是編譯可以控制的事情。
二、異常類的繼承和處理機制。
下一個程序卻能編譯經過:爲何程序中未給出ExceptionB的catch處理,可是仍然可以編譯經過。
這是由於添加了catch(Exception a)模塊,使得全部的異常都能被catch。這是爲何呢?
由於Exception是全部異常類的基類,包括Java中的常規異常:
catch模塊會對try中捕獲到的異常對象(一次只可能產生一個異常對象),依次的進行匹配,一旦匹配成功即轉入catch塊中進行相應的處理。
在匹配的過程當中,若是catch聲明的爲基類異常對象,那麼其導出類的異常對象是能夠被其正常捕獲的,即自動實現了向上的轉型!
Exception類爲全部異常類的基類,故編譯器認爲ExceptionB對象能被catch,因此沒有產生編譯錯誤。
重要: catch(Exception e){}又被稱爲捕獲所有異常對象,經常用於放在最後一個catch中,保證全部意料以外的異常對象都能被捕獲。
catch(Exception e)雖然能捕獲全部異常對象,可是其處理方法卻只能有一種,無針對性,對任何意料以外的異常都要適用。因此其處理方法通常爲將捕獲的異常對象的信息經過e.printStackTrace()方法輸出到控制檯,以提醒程序員何種意料以外的異常發生了。
機制:對於同一個try塊,Java不容許catch(基類)出如今catch(相應導出類)以前,以覆蓋了更好的異常處理方法。
Java中容許對異常進行再次拋出,以提交給上一層進行處理,最爲明顯的例子爲Java的常規異常。
常規異常:有Java所定義的異常,不須要異常聲明,在未被try-catch的狀況下,會被默認上報到main()方法。
Example:
|
當從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的異常信息被重寫,從其被從寫處從新記錄!