丟擲異常

以下示例顯示了丟擲異常的基礎知識:

public void checkNumber(int number) throws IllegalArgumentException {
    if (number < 0) {
        throw new IllegalArgumentException("Number must be positive: " + number);
    }
}

在第 3 行丟擲異常。本宣告可分為兩部分:

  • new IllegalArgumentException(...) 正在建立 IllegalArgumentException 類的例項,並帶有描述異常報告錯誤的訊息。

  • 然後 throw ... 丟擲異常物件。

丟擲異常時,會導致封閉語句異常終止,直到處理**異常為止。這在其他示例中描述。

最好在單個語句中建立和丟擲異常物件,如上所示。在異常中包含有意義的錯誤訊息也是一種很好的做法,可以幫助程式設計師理解問題的原因。但是,這不一定是你應向終端使用者顯示的訊息。 (首先,Java 沒有直接支援國際化異常訊息。)

還有幾點要做:

  • 我們宣稱 checkNumberthrows IllegalArgumentException。這不是絕對必要的,因為 IllegalArgumentException 是一個經過檢查的例外; 請參閱 Java 異常層次結構 - 未選中和已檢查的異常 。但是,最好這樣做,並且還要包含丟擲方法的 javadoc 註釋的異常。

  • 無法訪問 throw 語句後的程式碼。因此,如果我們寫這個:

     throw new IllegalArgumentException("it is bad");
     return;
    

    編譯器將報告 return 語句的編譯錯誤。

連結異常

除了傳統的 message 引數之外,許多標準異常都有一個帶有第二個 cause 引數的建構函式。cause 允許你連結異常。這是一個例子。

首先,我們定義一個未經檢查的異常,當我們的應用程式遇到不可恢復的錯誤時,它會丟擲。請注意,我們已經包含了一個接受 cause 引數的建構函式。

    public class AppErrorException extends RuntimeException {
        public AppErrorException() {
            super();
        }

        public AppErrorException(String message) {
            super(message);
        }

        public AppErrorException(String message, Throwable cause) {
            super(message, cause);
        }
    }

接下來,這是一些說明異常連結的程式碼。

    public String readFirstLine(String file) throws AppErrorException {
        try (Reader r = new BufferedReader(new FileReader(file))) {
            String line = r.readLine();
            if (line != null) {
                return line;
            } else {
                throw new AppErrorException("File is empty: " + file);
            }
        } catch (IOException ex) {
            throw new AppErrorException("Cannot read file: " + file, ex);
        }
    }

try 塊中的 throw 檢測到問題並通過簡單訊息通過異常報告。相比之下,catch 塊中的 throw 通過將其包裝在新的(已檢查)異常中來處理 IOException。但是,它並沒有丟掉原來的例外。通過將 IOException 作為 cause 傳遞,我們將其記錄下來,以便可以在堆疊跟蹤中列印,如建立和讀取堆疊跟蹤中所述。