这是代码。
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块抛出的异常抑制了资源异常,我得到了#34;抑制异常:1"起初这是可以理解的。但是当最后抛出异常时,似乎所有被抑制的异常都消失了,因为我得到了#34; java.lang.Exception:来自最终的异常"其次是"抑制异常:0"我认为它应该 1 。 我浏览了Java教程,它肯定会说
但是,在此示例中,如果方法readLine并关闭两个抛出异常,则方法readFirstLineFromFileWithFinallyBlock将抛出finally块抛出的异常;从try块抛出的异常被抑制。
来自The try-with-resources Statement
怎么可能发生?
答案 0 :(得分:1)
以下代码可以满足您的期望:
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部分(如JDK 1.7.0中所介绍的那样),看看会发生什么(有关详细信息,请参阅What is the Java 7 try-with-resources bytecode equivalent using try-catch-finally?):
MyResource r = new MyResource("resource")
IllegalArgumentException
close()
(在您的示例中只有一个)close()
抛出异常,但由于try块中的异常具有优先级,close()
抛出的异常被抑制并通过addSuppressed(..)
添加因此,该部分的工作方式与您阅读本教程时的预期相同。
现在是代码的try-catch-finally部分(如在JDK 1.6及更早版本中):
IllegalArgumentException
但是这次在java教程中使用的 抑制 这个词并不代表"被抑制并添加到实际抛出的异常中#34; 但"被压制并迷失为天堂" 。因此它仍然像在JDK 1.6及更早版本中那样运行,并且不使用新引入的addSuppressed(..)
getSuppressed()
功能。这就是它没有像你期望的那样表现的原因。
我认为你所期望的行为也不符合逻辑。我希望它表现得像这样:
...
} finally {
try {
new MyResource("finally").close();
} catch (Exception e) {
if (exceptionFromCatch!=null) {
exceptionFromCatch.addSuppressed(e);
} else {
throw e;
}
}
}
...
这总是优先考虑try块中的异常(使用新的try-with-resource特性实现),并将catch块中的异常添加到列表中。但这会破坏与JDK 1.6的兼容性,所以我想这就是为什么它不会表现得那样。