Java SE 6 技術手冊

10.3 throw、throws

當程式發生錯誤而無法處理的時候,會丟出對應的例外物件,除此之外,在某些時刻,您可能會想要自行丟出例外,例如在捕捉例外並處理結束後,再將例外丟出,讓下一層例外處理區塊來捕捉;另一個狀況是重新包裝例外,將捕捉到的例外以您自己定義的例外物件加以包裝丟出。若想要自行丟出例外,您可以使用 "throw" 關鍵字,並生成指定的例外物件,例如:

throw new ArithmeticException();

舉個例子來說明,在 Java 的除法中,允許浮點數運算時除數為 0,所得到的結果是 Infinity,也就是無窮數,如果您想要自行檢驗除零錯誤,可以自行丟出 ArithmeticException 例外,這個例外是在整數除法且為除數 0 時所引發的例外,您可以讓浮點數運算除數為 0 時也丟出這個例外。

範例 10.3 ThrowDemo.java

public class ThrowDemo { 
    public static void main(String[] args) { 
        try {
            double data = 100 / 0.0;
            System.out.println("浮點數除以零:" + data); 
            if(String.valueOf(data).equals("Infinity")) 
                throw new ArithmeticException("除零例外");
        } 
        catch(ArithmeticException e) { 
            System.out.println(e); 
        } 
    } 
}

在檢驗運算結果為 Infinity 時,您自行建立 ArithmeticException 實例並使用 "throw" 丟出,產生實例的同時您可以指定訊息,執行結果如下:

浮點數除以零:Infinity
java.lang.ArithmeticException: 除零例外

在巢狀的 try...catch 結構時,必須注意該例外是由何者引發並由何者捕捉,例如:

範例 10.4 CatchWho.java

public class CatchWho { 
    public static void main(String[] args) { 
        try { 
            try { 
                throw new ArrayIndexOutOfBoundsException(); 
            } 
            catch(ArrayIndexOutOfBoundsException e) { 
               System.out.println(
                   "ArrayIndexOutOfBoundsException" +
                   "/內層try-catch"); 
            }

            throw new ArithmeticException(); 
        } 
        catch(ArithmeticException e) { 
            System.out.println("發生ArithmeticException"); 
        } 
        catch(ArrayIndexOutOfBoundsException e) { 
           System.out.println(
               "ArrayIndexOutOfBoundsException" +
               "/外層try-catch"); 
        } 
    } 
}

執行結果:

ArrayIndexOutOfBoundsException/內層try-catch
發生ArithmeticException

在範例 10.4 中,丟出的 ArrayIndexOutOfBoundsException 由內層的 "catch" 先捕捉到,由於內層已經捕捉了例外,所以外層的 "catch" 並不會捕捉到 ArrayIndexOutOfBoundsException 例外,如果內層的 "catch" 並沒有捕捉到這個例外,則外層的 "catch" 就有機會捕捉這個例外,例如範例 10.5 中 ArrayIndexOutOfBoundsException 就會被外層的 "catch" 捕捉到。

範例 10.5 CatchWho2.java

public class CatchWho2 { 
    public static void main(String[] args) { 
        try {
            try { 
                throw new ArrayIndexOutOfBoundsException(); 
            } 
            catch(ArithmeticException e) { 
                System.out.println(
                    "ArrayIndexOutOfBoundsException" + 
                    "/內層try-catch"); 
            }

            throw new ArithmeticException(); 
        } 
        catch(ArithmeticException e) { 
            System.out.println("發生ArithmeticException"); 
        } 
        catch(ArrayIndexOutOfBoundsException e) { 
            System.out.println(
                "ArrayIndexOutOfBoundsException" + 
                "/外層try-catch"); 
        } 
    } 
}

執行結果:

ArrayIndexOutOfBoundsException/外層try-catch

如果您在方法中會有例外的發生,而您並不想在方法中直接處理,而想要由呼叫方法的呼叫者來處理,則您可以使用 "throws" 關鍵字來宣告這個方法將會丟出例外,例如 java.ioBufferedReader 的 readLine() 方法就聲明會丟出 java.io.IOException。使用 "throws" 聲明丟出例外的時機,通常是工具類別的某個工具方法,因為作為被呼叫的工具,本身並不需要將處理例外的方式給定義下來,所以在方法上使用"throws"聲明會丟出例外,由呼叫者自行決定如何處理例外是比較合適的,您可以如下使用 "throws" 來丟出例外:

private void someMethod(int[] arr) throws 
                ArrayIndexOutOfBoundsException, 
                ArithmeticException { 
    // 實作 
}

注意方法上若會丟出多種可能的例外時,中間是使用逗點分隔;當方法上使用 "throws" 宣告丟出例外時,意味著呼叫該方法的呼叫者必須處理這些例外,範例 10.6 是 "throws" 的簡單示範。

範例 10.6 ThrowsDemo.java

public class ThrowsDemo { 
    public static void main(String[] args) { 
        try { 
            throwsTest(); 
        } 
        catch(ArithmeticException e) { 
            System.out.println("捕捉例外"); 
        } 
    }

    private static void throwsTest() 
                           throws ArithmeticException { 
        System.out.println("這只是一個測試"); 
        // 程式處理過程假設發生例外 
        throw new ArithmeticException(); 
    } 
}

執行結果:

這只是一個測試
捕捉例外

簡單的說,您要不就在方法中直接處理例外,要不就在方法上宣告該方法會丟回例外,由呼叫它的呼叫者來處理例外。

良葛格的話匣子 您也可以在定義介面(interface)時於方法上聲明"throws"某些類型的例外,然而要小心使用,因為若您在這些方法中發生了某些不是方法聲明的例外,您就無法將之"throw",只能自行撰寫一些try..catch來暗自處理掉,或者是重新包裝例外為"throws"上所聲明的例外,或者是將該例外包裝為RuntimeException然後再丟出。