最后使用时抑制的异常消失了吗?
Suppressed exception disappeared when using finally?
这是代码。
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 块抛出的异常抑制了资源的异常,所以我一开始得到 "suppressed exceptions: 1",这是可以理解的。但是当最后抛出异常时,似乎所有被抑制的异常都消失了,因为我得到 "java.lang.Exception: exception from finally" 后跟 "suppressed exceptions: 0",我认为它应该是 1。
我浏览了 Java 教程,它肯定是
However, in this example, if the methods readLine and close both throw exceptions, then the method readFirstLineFromFileWithFinallyBlock throws the exception thrown from the finally block; the exception thrown from the try block is suppressed.
来自The try-with-resources Statement
怎么会这样?
下面的代码可以满足您的预期:
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? 了解更多详情):
- try-with-resource 块
MyResource r = new MyResource("resource")
已执行
- 执行 try 块并抛出
IllegalArgumentException
- try-with-resource 块为所有资源调用
close()
(在您的示例中只有一个)
close()
抛出异常,但由于 try 块中的异常具有优先级,因此 close()
抛出的异常被抑制并通过 addSuppressed(..)
添加
因此该部分的工作方式与您阅读本教程时预期的一样。
现在是代码的 try-catch-finally 部分(如 JDK 1.6 及更早版本):
- 执行 try 块并抛出
IllegalArgumentException
- (catch 块的行为与没有 catch 块的行为相同)
- 执行 finally 块并抛出异常
- 来自 finally 块的异常优先,来自 try 块的异常被抑制
但是这次suppressed这个词在java教程中并不代表"suppressed and added to the actually thrown exception" 但 "suppressed and lost to nirvana"。所以它的行为仍然与 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 的兼容性,所以我想这就是它不那样做的原因。
这是代码。
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 块抛出的异常抑制了资源的异常,所以我一开始得到 "suppressed exceptions: 1",这是可以理解的。但是当最后抛出异常时,似乎所有被抑制的异常都消失了,因为我得到 "java.lang.Exception: exception from finally" 后跟 "suppressed exceptions: 0",我认为它应该是 1。 我浏览了 Java 教程,它肯定是
However, in this example, if the methods readLine and close both throw exceptions, then the method readFirstLineFromFileWithFinallyBlock throws the exception thrown from the finally block; the exception thrown from the try block is suppressed.
来自The try-with-resources Statement
怎么会这样?
下面的代码可以满足您的预期:
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? 了解更多详情):
- try-with-resource 块
MyResource r = new MyResource("resource")
已执行 - 执行 try 块并抛出
IllegalArgumentException
- try-with-resource 块为所有资源调用
close()
(在您的示例中只有一个) close()
抛出异常,但由于 try 块中的异常具有优先级,因此close()
抛出的异常被抑制并通过addSuppressed(..)
添加
因此该部分的工作方式与您阅读本教程时预期的一样。
现在是代码的 try-catch-finally 部分(如 JDK 1.6 及更早版本):
- 执行 try 块并抛出
IllegalArgumentException
- (catch 块的行为与没有 catch 块的行为相同)
- 执行 finally 块并抛出异常
- 来自 finally 块的异常优先,来自 try 块的异常被抑制
但是这次suppressed这个词在java教程中并不代表"suppressed and added to the actually thrown exception" 但 "suppressed and lost to nirvana"。所以它的行为仍然与 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 的兼容性,所以我想这就是它不那样做的原因。