Exception JDK 1.7可丢弃的'addsupprested()'方法

Exception JDK 1.7可丢弃的'addsupprested()'方法,exception,jvm,java,java-7,Exception,Jvm,Java,Java 7,好吧,我通过相关的问题,我读了JDK1.7的源代码,但我没有找到答案 在这个问题上,我想完全忽略fillInStackTrace 从JDK 1.4开始,添加了initCause()方法。例如,当您使用核心反射来调用方法时,您会收到InvocationTargetException,其中包含目标异常的原因 当我看到这个特性时,我也开始在这样的场景中使用它 try { //contains some code that can throw new IOException();

好吧,我通过相关的问题,我读了JDK1.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()
,以便在外部块中正确处理此异常

这是JDK1.7之前的情况。为什么以及何时应该使用
addsupprested()
?我应该把上面的代码改成

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        RuntimeException re= new RuntimeException(e.getMessage());
        re.addSuppressed(e);
        throw re;
    }
作为一个额外的问题,
addsupprested()
为什么不像
initCause()
那样返回
Throwable()
以允许
抛出(RuntimeException)新的RuntimeException()。initCause(e)?例如,为什么我不能这样做

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

我将答案提取到另一篇文章。如果在finally块中执行的代码抛出异常,则将保存被抑制的异常。这是一个你可能不关心的例外。在Java 6中,finally块中的此类异常将成为调用代码将看到的唯一异常,但在新的try with resource块中,调用代码将看到原始异常,而在虚拟finally块中发生的异常将在getsupprested()中


在您的情况下,只需继续包装原始异常作为新异常的原因。

一般来说,当我们以某种方式并行执行时,应该使用Throwable
addsupprested()
方法,它可以产生异常,即被抑制的异常。我发现了两个例子

  • 当调用代码将看到原始异常(在Try或catch块中)和在finally块中发生的异常时,请尝试使用资源块(Try finally块)

  • 批处理作业(批量操作),无论当前项上的操作是否成功,都应继续执行下一项

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

try-finally块中的默认行为,其中有2个异常,即原始异常被抑制,并且我们只看到finally块中的异常。如果我们使用finally block on来关闭资源,那么我们确实希望看到原始异常,但也可以选择看到finally块中的异常,这会关闭资源并失败

从第7版开始,平台支持抑制异常的概念(与try with resources语句结合使用)。为了传递异常而被抑制的任何异常都会在堆栈跟踪下打印出来

首先,我们应该阅读一下try with resource新特性。例如,你可以在这里阅读,也可以在这里阅读。简言之,在某种意义上,您可以有2个并行的Throwable,通常是从您的try块和finally块开始。旧的try-catch语义将从finally块返回异常,而从try块返回异常(或从catch块返回异常)。新的“资源试用”功能使您能够获得这两个异常。更重要的是,您将收到原始异常,其中来自finally块的异常将被抑制

请注意,当一个异常导致另一个异常时,通常会捕获第一个异常,然后抛出第二个异常作为响应。换句话说,这两个例外之间存在因果关系。相反,在某些情况下,可以在兄弟代码块中抛出两个独立的异常,特别是在try with resources语句的try块和编译器生成的finally块中,后者关闭资源。在这些情况下,只能传播一个抛出的异常。在try with resources语句中,当存在两个这样的异常时,将传播源自try块的异常,并将来自finally块的异常添加到由try块的异常抑制的异常列表中。当异常展开堆栈时,它会累积多个被抑制的异常

示例:

    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()引发IOException{
SecurityManager security=System.getSecurityManager();
if(安全性!=null){
checkPermission(新的运行时权限(“closeClassLoader”);
}
列表错误=ucp.closeLoaders();
//现在关闭所有剩余的流。
已同步(可关闭){
Set keys=closeables.keySet();
用于(可关闭c:键){
试一试{
c、 close();
}捕获(IOException ioex){
错误。添加(ioex);
}
}
closeables.clear();
}
if(errors.isEmpty()){
返回;
}
IOException firstex=错误。删除(0);
//抑制任何剩余的异常
for(IOException错误:错误){
**firstex.addsupprested(错误)**
}
扔第一个;
}
一般来说,这种方法可以在批处理作业(批量操作)中使用,此时我们应该继续执行下一项(关闭下一个打开的流,如本例中所示),而不管
 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;
}