Java - 检测在“finally”块期间是否有正在进行的异常

Mat*_*eak 5 java exception finally

我正在从 Java 语言规范中考虑这一点:

如果 catch 块由于原因 R 突然完成,则执行 finally 块。然后有一个选择:

  • 如果 finally 块正常完成,则 try 语句由于原因 R 突然完成。

  • 如果 finally 块因原因 S 突然完成,则 try 语句因原因 S 突然完成(并且原因 R 被丢弃)。

我有一个块如下:

try {
  .. do stuff that might throw RuntimeException ...
} finally {
  try {
    .. finally block stuff that might throw RuntimeException ...
  } catch {
    // what to do here???
  }
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望块中的任何RuntimeException抛出finally都能逃脱,前提是它不会导致RuntimeExceptiontry块中的抛出被丢弃

Java 中有什么方法可以让我知道与块关联的finally块是否正常完成?

我猜我可以将 a 设置boolean为主try块的最后一个语句(例如,completedNormally = true这是最好的方法,还是有更好/更标准的东西?

sp0*_*00m 5

我相信关键是不要失去原来的原因。

如果我们看看 try-with-resources 的行为:

private static class SomeAutoCloseableThing implements AutoCloseable {

    @Override
    public void close() {
        throw new IllegalStateException("closing failed");
    }

}

public static void main(String[] args) {
    try (SomeAutoCloseableThing thing = new SomeAutoCloseableThing()) {
        throw new IllegalStateException("running failed");
    }
}
Run Code Online (Sandbox Code Playgroud)

我们最终得到:

Exception in thread "main" java.lang.IllegalStateException: running failed
    at Main.main(Main.java:16)
    Suppressed: java.lang.IllegalStateException: closing failed
        at Main$SomeAutoCloseableThing.close(Main.java:9)
        at Main.main(Main.java:17)
Run Code Online (Sandbox Code Playgroud)

这个堆栈跟踪很棒,因为我们看到了两个异常,即我们不会丢失running failed一个。


在没有 try-with-resources 的情况下实现这一点,错误的方式:

Exception in thread "main" java.lang.IllegalStateException: running failed
    at Main.main(Main.java:16)
    Suppressed: java.lang.IllegalStateException: closing failed
        at Main$SomeAutoCloseableThing.close(Main.java:9)
        at Main.main(Main.java:17)
Run Code Online (Sandbox Code Playgroud)

我们最终得到:

Exception in thread "main" java.lang.IllegalStateException: closing failed
    at Main$SomeAutoCloseableThing.close(Main.java:9)
    at Main.main(Main.java:19)
Run Code Online (Sandbox Code Playgroud)

我们不知道这种running failed情况也发生了,因为我们打破了控制流,如果您需要调试这种情况,那是非常糟糕的。


在没有 try-with-resources 的情况下实现这一点,正确的方法(在我看来)是“记录并忘记”finally块中发生的异常:

public static void main(String[] args) {
    SomeAutoCloseableThing thing = new SomeAutoCloseableThing();
    try {
        throw new IllegalStateException("running failed");
    } finally {
        thing.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们最终得到:

17:10:20.030 [main] ERROR Main - An error occurred while closing SomeAutoCloseableThing
java.lang.IllegalStateException: closing failed
    at Main$SomeAutoCloseableThing.close(Main.java:10) ~[classes/:?]
    at Main.main(Main.java:21) [classes/:?]
Exception in thread "main" java.lang.IllegalStateException: running failed
    at Main.main(Main.java:18)
Run Code Online (Sandbox Code Playgroud)

不如 try-with-resources 方法,但至少我们知道实际发生了什么,没有丢失任何东西。