跳到内容

嵌套异常

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

待办事项
添加一些类似于变量中的练习


华夏公益教科书