Java SE 6 技術手冊

10.1 例外處理入門

回憶一下 6.2.1 中介紹過的「命令列引數」(Command line argument),在還沒有學會使用Java的例外處理之前,為了確定使用者是否有提供引數,您可能要先檢查引數的陣列長度是否為 0,以免程式存取超過陣列長度而發生錯誤:

if(args.length == 0) {
    // 使用者沒有指定引數,顯示引數功能畫面
}
else {
    // 執行所指定引數的對應功能
}

利用條件判斷式來避免錯誤的發生,這樣的檢查方式在一些程式語言中經常出現,然而顯然的,處理錯誤的邏輯與處理業務的邏輯混在一起,如果更多的錯誤狀況必須檢查的話,程式會更難以閱讀,且由於使用了一些判斷式,即使發生機率低的錯誤,也都必須一視同仁的進行判斷檢查,這會使得程式的執行效能受到一定程度的影響。

Java 的例外處理機制可以協助您避開或是處理程式可能發生的錯誤,「例外」(Exception)在 Java 中代表一個錯誤的實體物件,在特定錯誤發生時會丟出特定的例外物件,有些預期中可能發生的例外,編譯器會提醒您先行處理,對於一些程式運行時所發生的執行時期例外,您有機會捕捉這些例外,並嘗試將程式回復至正常運作狀態。

在 Java 中如果想嘗試捕捉例外,可以使用 "try"、"catch"、"finally" 三個關鍵字組合的語法來達到,其語法基本結構如下:

try {
    // 陳述句
}
catch(例外型態 名稱) {
    // 例外處理
}
finally {
    // 一定會處理的區塊
}

一個 "try" 語法所包括的區塊,必須有對應的 "catch" 區塊或是 "finally" 區塊,"try" 區塊可以搭配多個 "catch" 區塊,如果有設定 "catch" 區塊,則 "finally" 區塊可有可無,如果沒有定義 "catch" 區塊,則一定要有 "finally" 區塊。

使用實例來說明,您可以使用 try...catch 語法來取代命令列引數的陣列長度檢查動作,如範例 10.1 所示。

範例 10.1 CheckArgsDemo.java

public class CheckArgsDemo {
    public static void main(String[] args) {
        try {
            System.out.printf("執行 %s 功能%n", args[0]);
        }
        catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("沒有指定引數");
            e.printStackTrace();
        }
    }
}

如果在執行程式時沒有指定引數,那麼args陣列的長度是 0,程式中嘗試從 args[0] 取得引數時就會發生錯誤,錯誤的實例是 ArrayIndexOutOfBoundsException,這個實例會在被對應的 "catch" 所捕捉,在範例 10.1 中被捕捉的例外指定給 e 名稱來參考,例外被捕捉後會執行對應的 "catch" 區塊,在範例中是顯示提示訊息,並使用 printStackTrace() 會顯示完整的例外訊息,沒有指定引數時的執行結果如下:

>java CheckArgsDemo
沒有指定引數
java.lang.ArrayIndexOutOfBoundsException: 0
        at CheckArgsDemo.main(CheckArgsDemo.java:4)

範例 10.1 中並沒有使用條件判斷式來檢查陣列長度,也就是沒有使用 if 陳述句,例外處理只有在錯誤真正發生,也就是丟出例外時才處理,所以與使用 if 判斷式每次都要進行檢查動作相比,效率上會好一些,要注意的是,例外處理最好只用於錯誤處理,而不應是用於程式業務邏輯的一部份,因為例外的產生要消耗資源,例如以下應用例外處理的方式就不適當:

while(true) {
    try {
        System.out.println(args[i]);
        i++;
    }
    catch(ArrayIndexOutOfBoundsException e) {
        break;
    }
}

循序取出陣列值時,最後一定會到達陣列的邊界,檢查邊界是必要的動作,是程式業務邏輯的一部份,而不是錯誤處理邏輯的一部份,您該使用的是 for 迴圈而不是依賴例外處理,例如下面的方式才是正確的:

for(int i = 0; i < args.length; i++) {
    System.out.println(args[i]);
}