Java未被捕獲的異常<br />在你學習在程序中處理異常之前,看一看如果你不處理它們會有什麼情況發生是很有好處的。下面的小程序包括一個故意導致被零除錯誤的表達式。
class Exc0 { public static void main(String args[]) { int d = 0; int a = 42 / d; }}
當Java運行時系統檢查到被零除的情況,它構造一個新的異常對象然後拋出該異常。這導致Exc0的執行停止,因為一旦一個異常被拋出,它必須被一個異常處理程序捕獲並且被立即處理。該例中,我們沒有提供任何我們自己的異常處理程序,所以異常被Java運行時系統的默認處理程序捕獲。任何不是被你程序捕獲的異常最終都會被該默認處理程序處理。默認處理程序顯示一個描述異常的字符串,打印異常發生處的堆棧軌跡並且終止程序。
下面是由標準javaJDK運行時解釋器執行該程序所產生的輸出:
java.lang.ArithmeticException: / by zero at Exc0.main(Exc0.java:4)
注意,類名Exc0,方法名main,文件名Exc0.java和行數4是怎樣被包括在一個簡單的堆棧使用軌跡中的。還有,注意拋出的異常類型是Exception的一個名為ArithmeticException的子類,該子類更明確的描述了何種類型的錯誤方法。本章後面部分將討論,Java提供多個內置的與可能產生的不同種類運行時錯誤相匹配的異常類型。
堆棧軌跡將顯示導致錯誤產生的方法調用序列。例如,下面是前面程序的另一個版本,它介紹了相同的錯誤,但是錯誤是在main( )方法之外的另一個方法中產生的:
class Exc1 { static void subroutine() { int d = 0; int a = 10 / d; } public static void main(String args[]) { Exc1.subroutine(); }}
默認異常處理器的堆棧軌跡結果表明了整個調用棧是怎樣顯示的:
java.lang.ArithmeticException: / by zero at Exc1.subroutine(Exc1.java:4) at Exc1.main(Exc1.java:7)
如你所見,棧底是main的第7行,該行調用了subroutine( )方法。該方法在第4行導致了異常。調用堆棧對於調試來說是很重要的,因為它查明了導致錯誤的精確的步驟。
Java try語句的嵌套
Try語句可以被嵌套。也就是說,一個try語句可以在另一個try塊內部。每次進入try語句,異常的前後關係都會被推入堆棧。如果一個內部的try語句不含特殊異常的catch處理程序,堆棧將彈出,下一個try語句的catch處理程序將檢查是否與之匹配。這個過程將繼續直到一個catch語句匹配成功,或者是直到所有的嵌套try語句被檢查耗盡。如果沒有catch語句匹配,Java的運行時系統將處理這個異常。下面是運用嵌套try語句的一個例子:
// An example of nested try statements.class NestTry { public static void main(String args[]) { try { int a = args.length; /* If no command-line args are present,the following statement will generate a divide -by-zero exception. */ int b = 42 / a; System.out.println("a = " + a); try { // nested try block /* If one command-line arg is used,then a divide -by-zero exception will be generated by the following code. */ if(a==1) a = a/(aa); // division by zero /* If two command-line args are used,then generate an out -of-bounds exception. */ if(a==2) { int c[] = { 1 }; c[42] = 99; // generate an out-of-bounds exception } } catch(ArrayIndexOutOfBoundsException e) { System.out.println("Array index out-of-bounds: " + e); } } catch(ArithmeticException e) { System.out.println("Divide by 0: " + e); } }}
如你所見,該程序在一個try塊中嵌套了另一個try塊。程序工作如下:當你在沒有命令行參數的情況下執行該程序,外面的try塊將產生一個被零除的異常。程序在有一個命令行參數條件下執行,由嵌套的try塊產生一個被零除的錯誤。因為內部的塊不匹配這個異常,它將把異常傳給外部的try塊,在那裡異常被處理。如果你在具有兩個命令行參數的條件下執行該程序,由內部try塊產生一個數組邊界異常。下面的結果闡述了每一種情況:
C:/>java NestTryDivide by 0: java.lang.ArithmeticException: / by zeroC:/>java NestTry Onea = 1Divide by 0: java.lang.ArithmeticException: / by zeroC:/>java NestTry One Twoa = 2Array index out- of-bounds: java.lang.ArrayIndexOutOfBoundsException
當有方法調用時,try語句的嵌套可以很隱蔽的發生。例如,你可以把對方法的調用放在一個try塊中。在該方法內部,有另一個try語句。這種情況下,方法內部的try仍然是嵌套在外部調用該方法的try塊中的。下面是前面例子的修改,嵌套的try塊移到了方法nesttry( )的內部:
/* Try statements can be implicitly nested via calls to methods. */class MethNestTry { static void nesttry(int a) { try { // nested try block /* If one command-line arg is used,then a divide-by- zero exception will be generated by the following code. */ if(a==1) a = a/(aa); // division by zero /* If two command-line args are used,then generate an out-of- bounds exception. */ if(a==2) { int c[] = { 1 }; c[42] = 99; // generate an out-of-bounds exception } } catch(ArrayIndexOutOfBoundsException e) { System.out .println("Array index out-of-bounds: " + e); } } public static void main(String args[]) { try { int a = args.length; /* If no command-line args are present, the following statement will generate a divide-by-zero exception. */ int b = 42 / a; System.out.println("a = " + a); nesttry(a); } catch(ArithmeticException e) { System. out.println("Divide by 0: " + e); } }}
該程序的輸出與前面的例子相同。