Java 最终使用时抑制的异常消失?

Java 最终使用时抑制的异常消失?,java,exception,try-with-resources,Java,Exception,Try With Resources,这是密码 public class TestTest { public static void main (String[] args) throws Exception { try { run(); } catch(Exception e) { printSuppressedExceptions(e); } } public static void printSuppres

这是密码

public class TestTest {
    public static void main (String[] args) throws Exception {
        try {
            run();
        } catch(Exception e) {
            printSuppressedExceptions(e);
        }
    }

    public static void printSuppressedExceptions(Throwable t) {
        System.out.println(t);
        System.out.println("suppressed exceptions: " + t.getSuppressed().length);
    }

    public static void run() throws Exception {
        try(MyResource r = new MyResource("resource");) {
            System.out.println("try");
            System.getProperty("").length(); // throws illegalArgumentException
        } catch(Exception e) {
            printSuppressedExceptions(e);
            throw e;
        } finally {
            new MyResource("finally").close();
        }
    }   
}

class MyResource implements AutoCloseable {
    private final String name;

    public MyResource(String name) {
        this.name = name;
    }

    @Override
    public void close() throws Exception {
        throw new Exception("exception" + " from " + this.name);
    }
}    
因为从try块抛出的异常抑制了来自资源的异常,所以我首先得到了“抑制的异常:1”,这是可以理解的。但是当一个异常从finally抛出时,似乎所有被抑制的异常都消失了,因为我得到了“java.lang.exception:exception from finally”,然后是“被抑制的异常:0”,我认为它应该是1。 我浏览了Java教程,它明确地说

但是,在本例中,如果readLine和close方法都抛出异常,那么readFirstLineFromFileWithFinallyBlock方法抛出finallyblock块抛出的异常;从try块引发的异常被抑制


它是如何发生的?

以下是实现您期望的功能的代码:

public class TestTest {
    public static void main (String[] args) throws Exception {
        try {
            run();
        } catch(Exception e) {
            printSuppressedExceptions(e);
        }
    }

    public static void printSuppressedExceptions(Throwable t) {
        System.out.println(t);
        System.out.println("suppressed exceptions (" + t.getSuppressed().length + "):");
        for (Throwable suppressed : t.getSuppressed()) {
            System.out.println("  - " + suppressed);
        }
    }

    public static void run() throws Exception {
        Exception exceptionFromCatch = null;
        try(MyResource r = new MyResource("resource");) {
            System.out.println("try");
            System.getProperty("").length(); // throws illegalArgumentException
        } catch(Exception e) {
            exceptionFromCatch = e;
            printSuppressedExceptions(e);
            throw e;
        } finally {
            try {
                new MyResource("finally").close();
            } catch (Exception e) {
                if (exceptionFromCatch!=null) {
                    e.addSuppressed(exceptionFromCatch);
                }
                throw e;
            }
        }
    }   
}

class MyResource implements AutoCloseable {
    private final String name;

    public MyResource(String name) {
        this.name = name;
    }

    @Override
    public void close() throws Exception {
        throw new Exception("exception" + " from " + this.name);
    }
}
因此,让我们来看看代码的try-with-resource部分(如JDK1.7.0中介绍的),看看会发生什么(有关更多详细信息,请参阅):

  • 执行try with resource块
    MyResource r=newmyresource(“资源”)
  • 执行try块并抛出一个
    IllegalArgumentException
  • try with resource块调用所有资源的
    close()
    (在您的示例中仅一个)
  • close()
    引发异常,但由于try块中的异常具有优先级,因此
    close()
    引发的异常被抑制,并通过
    addsupprested(..)添加。
因此,该部分的工作原理与您阅读本教程所期望的一样

现在是代码的try-catch-finally部分(如JDK 1.6及更早版本):

  • 执行try块并抛出一个
    IllegalArgumentException
  • (捕捉块的行为方式与没有捕捉块时相同)
  • 执行finally块并抛出异常
  • 来自finally块的异常具有优先级,而来自try块的异常被抑制
但是这次java教程中使用的supprested一词并不代表“抑制并添加到实际抛出的异常中”,而是“抑制并迷失在涅盘中”。因此,它的行为仍与JDK1.6及更早版本相同,并且没有使用新引入的
addsupprested(..)
getsupprested()
功能。这就是为什么它不像你期望的那样


我认为你所期望的行为也不符合逻辑。我希望它表现得像这样:

...
        } finally {
            try {
                new MyResource("finally").close();
            } catch (Exception e) {
                if (exceptionFromCatch!=null) {
                    exceptionFromCatch.addSuppressed(e);
                } else {
                    throw e;
                }
            }
        }
...

这将始终优先考虑try块中的异常(使用新的try with resource功能实现),并将catch块中的异常添加到列表中。但是这会破坏与JDK1.6的兼容性,所以我想这就是它不这样做的原因。

只是猜测:可能是这样,因为抛出了两个异常?当try with resources关闭r时,我期望从
r.close()
中得到一个,从finally块中创建并关闭的附加对象中得到另一个……此外,引用的文本引用了先前Java 7使用
try{read()}finally{close()}
的示例。我建议你读整段,然后继续读“抑制例外”一段。谢谢。我想@tuempl刚刚解决了我的困惑。但是这次java教程中使用的单词supprested并不是“supprested并添加到实际抛出的异常”而是“supprested and lost to nirvana”。啊哈,我想所有被抑制的异常都会添加到实际抛出的异常中,从1.7开始,这是完全错误的。