exception - JDK 1.7 可抛出的 `addSuppressed()` 方法

标签 exception jvm java java-7

好吧,我通过了相关问题,我阅读了JDK 1.7的源代码,但我没有找到答案。

在这个问题中我想完全忽略fillInStackTrace

从 JDK 1.4 开始,添加了 initCause() 方法。例如,当您使用核心反射来调用您收到 InvocationTargetException 的方法时,其中包含目标异常。

当我看到这个功能时,我也开始在这样的场景中使用它

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        throw new RuntimeException(e);
    }

所以,我捕获了一个异常,我还没准备好在这里处理它,我重新抛出一个新的异常,因为我有原始异常作为原因。在某些情况下不是 RuntimeException,而是使用了我的自定义异常,所以有时我也会调用 e.getCause() 以便在外部 block 中正确处理此异常。

这是 JDK 1.7 之前的情况。为什么以及何时应该使用 addSuppressed()?我是否应该将上面的代码更改为

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        RuntimeException re= new RuntimeException(e.getMessage());
        re.addSuppressed(e);
        throw re;
    }

还有一个额外的问题,为什么 addSuppressed() 不像 initCause() 那样返回 Throwable 允许 throw ( RuntimeException)new RuntimeException().initCause(e);?例如为什么我不能做?:

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        throw (RuntimeException)new RuntimeException(e.getMessage()).addSuppressed(e);
    }

我将答案提取到单独的帖子中。

最佳答案

一般来说,Throwable addSuppressed() 方法应该在我们以某种方式并行执行时使用,这会产生异常,抑制。我找到了 2 个例子;

  • Try-with-resource block (try-finally block ),当调用代码看到原始异常(在 try 或 catch block 中)和发生在 finally block 中的异常时。

  • 批处理作业(批量操作)无论对当前项目的操作是否成功,我们都应该继续进行下一个项目

在了解细节之前,正如@sarelbotha 所说,在我的例子中,我只需要继续包装原始异常作为我的新异常的原因。

try-finally block 中的默认行为,其中我们有 2 个异常,原始异常被抑制并且我们只看到来自 finally block 的异常。如果我们按顺序使用 finally block 来关闭资源,而不是我们真正希望看到原始异常,但我们也可以选择看到来自 finally block 的异常,它关闭了我们的资源并失败了。

As of release 7, the platform supports the notion of suppressed exceptions (in conjunction with the try-with-resources statement). Any exceptions that were suppressed in order to deliver an exception are printed out beneath the stack trace.

http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#printStackTrace%28%29

第一个应该阅读有关 try-with-resource 新功能的信息。你可以在这里阅读 http://www.baptiste-wicht.com/2010/08/java-7-try-with-resources-statement/例如或这里 What is the Java 7 try-with-resources bytecode equivalent using try-catch-finally? .简而言之,您可以在某种意义上并行拥有 2 个 Throwable,通常来自您的 try block 和您的 finally block 。旧的 try-catch 语义将从 finally block 返回异常,而 try block 中的 suppressed 异常(或从 catch block 中重新抛出异常)。新的 try-with-resource 功能使您能够同时获得这两个异常。更重要的是,您将收到原始异常,其中来自 finally block 的异常将被抑制

Note that when one exception causes another exception, the first exception is usually caught and then the second exception is thrown in response. In other words, there is a causal connection between the two exceptions. In contrast, there are situations where two independent exceptions can be thrown in sibling code blocks, in particular in the try block of a try-with-resources statement and the compiler-generated finally block which closes the resource. In these situations, only one of the thrown exceptions can be propagated. In the try-with-resources statement, when there are two such exceptions, the exception originating from the try block is propagated and the exception from the finally block is added to the list of exceptions suppressed by the exception from the try block. As an exception unwinds the stack, it can accumulate multiple suppressed exceptions.

示例:

    public class TestClass {
static class ResourceA implements AutoCloseable{
      public void read() throws Exception{
        throw new Exception("ResourceA read exception");
      }
      @Override
      public void close() throws Exception {
        throw new Exception("ResourceA close exception");
      }
    };

static class ResourceB implements AutoCloseable{
      public void read() throws Exception{
        throw new Exception("ResourceB read exception");
      }
      @Override
      public void close() throws Exception {
        throw new Exception("ResourceB close exception");
      }
    };

    //a test method
    public static void test() throws Exception{
      try (ResourceA a = new ResourceA();
           //ResourceB b = new ResourceB()
              ) {
        a.read();
        //b.read();
      } catch (Exception e) {
        throw e;
      }
    }

    public static void main(String[] args)  throws Exception {
        test();
    }

输出如下:

Exception in thread "main" java.lang.Exception: ResourceA read exception
at TestClass$ResourceA.read(TestClass.java:6)
at TestClass.test(TestClass.java:29)
at TestClass.main(TestClass.java:39)
Suppressed: java.lang.Exception: ResourceA close exception
    at TestClass$ResourceA.close(TestClass.java:10)
    at TestClass.test(TestClass.java:31)
    ... 1 more

批处理作业(批量操作)。 好吧,我在 try-with-resources 之外发现了这种方法的一些用法。下面是来自 java.net.URLClassLoader.close

的源代码
 public void close() throws IOException {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkPermission(new RuntimePermission("closeClassLoader"));
    }
    List<IOException> errors = ucp.closeLoaders();
    // now close any remaining streams.
    synchronized (closeables) {
        Set<Closeable> keys = closeables.keySet();
        for (Closeable c : keys) {
            try {
                c.close();
            } catch (IOException ioex) {
                errors.add(ioex);
            }
        }
        closeables.clear();
    }
    if (errors.isEmpty()) {
        return;
    }
    IOException firstex = errors.remove(0);
    // Suppress any remaining exceptions
    for (IOException error: errors) {
        **firstex.addSuppressed(error);**
    }
    throw firstex;
}

一般来说,这种方法可以用于批处理作业(批量操作),当我们应该继续下一个项目时(关闭下一个打开的流,如本例所示),无论操作是否在当前项目是否成功。通过这种方式,正如我之前所说,我们可以通过某种方式并行执行,这会产生异常,抑制。在这种情况下,我们应该使用上面的方法抛出异常,并在其中保留被抑制的异常。

关于exception - JDK 1.7 可抛出的 `addSuppressed()` 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8946661/

相关文章:

java - 处理应用程序事件

java - 没有这样的方法错误: <init> when using rJava to create a new object

java - 在子类的构造函数中抛出异常

intellij-idea - 如何将 intellij 32bit xmlx 增加超过 1GB?

java - 将类文件(字节)解压到 ASM ClassNode 中

Android Gradle 无法为对象堆保留足够的空间

Java:同一个类中有多个 ActionListeners?

C++ 处理意外错误

java - 为什么在 .NET 中不检查异常?

java - 如何使用 JavaScript 覆盖类型 (GWT) 包装回调?