跳到內容

巢狀異常

75% developed
來自華夏公益教科書,開放的書籍,開放的世界

導航 異常 主題:v  d  e )


當捕獲異常時,異常包含堆疊跟蹤,它描述了錯誤並顯示異常發生的位置(即問題所在以及應用程式程式設計師應該檢視以解決問題的位置)。有時,希望捕獲異常並丟擲另一個異常。如果新異常保留對第一個異常的引用,則第一個異常稱為巢狀異常

Computer code 程式碼清單 6.4:NestingExceptionExample.java
public class NestingExceptionExample {
 
  public static void main(String[] args) throws Exception {
    Object[] localArgs = (Object[]) args;
   
    try {
      Integer[] numbers = (Integer[]) localArgs;
    } catch (ClassCastException originalException) {
      Exception generalException = new Exception(
        "Horrible exception!",
        originalException);
      throw generalException;
    }
  }
}
Standard input or output 程式碼清單 6.4 的輸出
Exception in thread "main" java.lang.Exception: Horrible exception!
at NestingExceptionExample.main(NestingExceptionExample.java:9)
Caused by: java.lang.ClassCastException: [Ljava.lang.String; incompatible with [Ljava.lang.Integer;
at NestingExceptionExample.main(NestingExceptionExample.java:7)

上面的程式碼是巢狀異常的示例。當丟擲Exception時,透過將ClassCastException物件引用作為引數傳遞,ClassCastException巢狀在新建的Exception中,其堆疊跟蹤被附加在一起。當捕獲Exception時,其堆疊跟蹤包含原始ClassCastException的堆疊跟蹤。

這是一種異常轉換,從一種異常轉換到另一種異常。例如,使用 RMI 呼叫遠端物件,呼叫方法必須處理RemoteException,如果通訊過程中出現錯誤,則丟擲此異常。從應用程式的角度來看,RemoteException沒有意義,它應該對應用程式使用遠端物件還是否透明。因此,RemoteException應該轉換為應用程式異常。

這種轉換也會隱藏錯誤的起源。堆疊跟蹤從異常丟擲時開始。因此,當我們捕獲並丟擲新異常時,堆疊跟蹤從丟擲新異常時開始,丟失了原始堆疊跟蹤。這對早期版本的 Java(1.4 之前)是正確的。從那時起,所謂的原因設施功能構建在Throwable類中。

一個可丟擲物件包含其執行緒在建立時執行堆疊的快照。它還可以包含一個訊息字串,提供有關錯誤的更多資訊。最後,它可以包含一個原因:另一個導致此可丟擲物件被丟擲的可丟擲物件。原因設施也被稱為鏈式異常設施,因為原因本身可以有一個原因,等等,從而導致一個異常的“鏈”,每個異常都是由另一個異常引起的。

可以透過兩種方式將原因與可丟擲物件關聯:透過採用原因作為引數的建構函式,或透過initCause(Throwable)方法。希望允許將原因與它們關聯的新可丟擲物件類應該提供採用原因的建構函式,並委託(可能間接)給採用原因的Throwable建構函式之一。例如

Example 程式碼部分 6.26:支援鏈的建構函式。
try {
    lowLevelOp();
} catch (LowLevelException le) {
    throw new HighLevelException(le);
}

由於 initCause 方法是公共的,它允許將原因與任何可丟擲物件關聯,即使是實現早於將異常鏈機制新增到 Throwable 的“遺留可丟擲物件”。例如

Example 程式碼部分 6.27:遺留建構函式。
try {
    lowLevelOp();
} catch (LowLevelException le) {
    throw (HighLevelException) new HighLevelException().initCause(le);
}

此外,從 1.4 版本開始,許多通用可丟擲物件類(例如ExceptionRuntimeExceptionError)已經過改造,具有接受原因的建構函式。由於存在initCause方法,這並不是嚴格必要的,但委託給接受原因的建構函式更方便且表達力更強。

按照慣例,類Throwable及其子類具有兩個建構函式,一個不帶引數,另一個帶一個 String 引數,該引數可用於生成詳細訊息。此外,那些可能與原因關聯的子類應該再有兩個建構函式,一個接受一個Throwable(原因),另一個接受一個 String(詳細訊息)和一個Throwable(原因)。


Clipboard

待辦事項
新增一些類似於變數中的練習


華夏公益教科書