返回介绍

9.2.5 重新掷出违例

发布于 2024-10-15 23:56:21 字数 4023 浏览 0 评论 0 收藏 0

在某些情况下,我们想重新掷出刚才产生过的违例,特别是在用 Exception 捕获所有可能的违例时。由于我们已拥有当前违例的句柄,所以只需简单地重新掷出那个句柄即可。下面是一个例子:

catch(Exception e) {

System.out.println("一个违例已经产生");

throw e;

}

重新“掷”出一个违例导致违例进入更高一级环境的违例控制器中。用于同一个 try 块的任何更进一步的 catch 从句仍然会被忽略。此外,与违例对象有关的所有东西都会得到保留,所以用于捕获特定违例类型的更高一级的控制器可以从那个对象里提取出所有信息。

若只是简单地重新掷出当前违例,我们打印出来的、与 printStackTrace() 内的那个违例有关的信息会与违例的起源地对应,而不是与重新掷出它的地点对应。若想安装新的堆栈跟踪信息,可调用 fillInStackTrace(),它会返回一个特殊的违例对象。这个违例的创建过程如下:将当前堆栈的信息填充到原来的违例对象里。下面列出它的形式:

//: Rethrowing.java
// Demonstrating fillInStackTrace()

public class Rethrowing {
  public static void f() throws Exception {
    System.out.println(
      "originating the exception in f()");
    throw new Exception("thrown from f()");
  }
  public static void g() throws Throwable {
    try {
      f();
    } catch(Exception e) {
      System.out.println(
        "Inside g(), e.printStackTrace()");
      e.printStackTrace();
      throw e; // 17
      // throw e.fillInStackTrace(); // 18
    }
  }
  public static void
  main(String[] args) throws Throwable {
    try {
      g();
    } catch(Exception e) {
      System.out.println(
        "Caught in main, e.printStackTrace()");
      e.printStackTrace();
    }
  }
} ///:~

其中最重要的行号在注释内标记出来。注意第 17 行没有设为注释行。它的输出结果如下:

originating the exception in f()
Inside g(), e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:8)
        at Rethrowing.g(Rethrowing.java:12)
        at Rethrowing.main(Rethrowing.java:24)
Caught in main, e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:8)
        at Rethrowing.g(Rethrowing.java:12)
        at Rethrowing.main(Rethrowing.java:24)

因此,违例堆栈路径无论如何都会记住它的真正起点,无论自己被重复“掷”了好几次。

若将第 17 行标注(变成注释行),而撤消对第 18 行的标注,就会换用 fillInStackTrace(),结果如下:

originating the exception in f()
Inside g(), e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:8)
        at Rethrowing.g(Rethrowing.java:12)
        at Rethrowing.main(Rethrowing.java:24)
Caught in main, e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.g(Rethrowing.java:18)
        at Rethrowing.main(Rethrowing.java:24)

由于使用的是 fillInStackTrace(),第 18 行成为违例的新起点。

针对 g() 和 main(),Throwable 类必须在违例规格中出现,因为 fillInStackTrace() 会生成一个 Throwable 对象的句柄。由于 Throwable 是 Exception 的一个基础类,所以有可能获得一个能够“掷”出的对象(具有 Throwable 属性),但却并非一个 Exception(违例)。因此,在 main() 中用于 Exception 的句柄可能丢失自己的目标。为保证所有东西均井然有序,编译器强制 Throwable 使用一个违例规范。举个例子来说,下述程序的违例便不会在 main() 中被捕获到:

//: ThrowOut.java
public class ThrowOut {
  public static void
  main(String[] args) throws Throwable {
    try {
      throw new Throwable(); 
    } catch(Exception e) {
      System.out.println("Caught in main()");
    }
  }
} ///:~

也有可能从一个已经捕获的违例重新“掷”出一个不同的违例。但假如这样做,会得到与使用 fillInStackTrace() 类似的效果:与违例起源地有关的信息会全部丢失,我们留下的是与新的 throw 有关的信息。如下所示:

//: RethrowNew.java
// Rethrow a different object from the one that
// was caught

public class RethrowNew {
  public static void f() throws Exception {
    System.out.println(
      "originating the exception in f()");
    throw new Exception("thrown from f()");
  }
  public static void main(String[] args) {
    try {
      f();
    } catch(Exception e) {
      System.out.println(
        "Caught in main, e.printStackTrace()");
      e.printStackTrace();
      throw new NullPointerException("from main");
    }
  }
} ///:~

输出如下:

originating the exception in f()
Caught in main, e.printStackTrace()
java.lang.Exception: thrown from f()
        at RethrowNew.f(RethrowNew.java:8)
        at RethrowNew.main(RethrowNew.java:13)
java.lang.NullPointerException: from main
        at RethrowNew.main(RethrowNew.java:18)

最后一个违例只知道自己来自 main(),而非来自 f()。注意 Throwable 在任何违例规范中都不是必需的。

永远不必关心如何清除前一个违例,或者与之有关的其他任何违例。它们都属于用 new 创建的、以内存堆为基础的对象,所以垃圾收集器会自动将其清除。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文