为什么try..finally阻止不将原始异常注册为抑制?

时间:2015-06-19 09:05:13

标签: java exception-handling try-finally

使用以下代码:

try {
    throw new RuntimeException ("main");
}
finally {
    throw new RuntimeException ("finally");
}

我得到了这个结果:

Exception in thread "main" java.lang.RuntimeException: finally
        at test.main(test.java:12)

但是,通过在Java 7中添加抑制的异常,当finally块本身因异常而失败时,语言将原始“主”异常注册为抑制是不合逻辑的?目前我必须手动模拟这个:

try {
    throw new RuntimeException ("main");
}
catch (RuntimeException exception) {
    try {
        throw new RuntimeException ("finally");
    }
    catch (RuntimeException exception2) {
        exception2.addSuppressed (exception);
        throw exception2;
    }
}

获得更多有用的(用于了解正在发生的事情)结果:

Exception in thread "main" java.lang.RuntimeException: finally
        at test.main(test.java:13)
        Suppressed: java.lang.RuntimeException: main
                at test.main(test.java:9)

编辑:澄清我在想什么。目前的Java版本是8,抑制异常不是一个全新的功能。但是try..finally仍然没有包含它们。是否存在阻止这种情况发生的事情?

2 个答案:

答案 0 :(得分:8)

因为try-with-resources是语法糖,Java编译器不会以相同的方式扩展常规的try-finally块。

看看以下代码:

try(FileInputStream fstream = new FileInputStream("test")) {
    fstream.read();
}

编译然后反编译(使用IntelliJ IDEA)时,它看起来像这样:

FileInputStream fstream = new FileInputStream("test");
Throwable var2 = null;

try {
    fstream.read();
} catch (Throwable var19) {
    var2 = var19;
    throw var19;
} finally {
    if(fstream != null) {
        if(var2 != null) {
            try {
                fstream.close();
            } catch (Throwable var17) {
                var2.addSuppressed(var17);
            }
        } else {
            fstream.close();
        }
    }
}

这段代码:

FileInputStream fstream = new FileInputStream("test");
try {
    fstream.read();
} finally {
    fstream.close();
}

在编译和反编译时看起来完全相同。

现在,可以肯定的是,所有finally块都应该以与上面相同的方式进行扩展,但由于某些原因而被忽略或决定反对。

我建议你open a feature request,因为我认为这是一个明智的功能。

答案 1 :(得分:5)

这不是一个权威的答案,但看起来这样的更改会破坏兼容性,或者try-with-resourcestry-finally会相互矛盾。

try-with-resources中的语义是传播try块引发的异常,并在调用注册为suppress的close()方法时抛出异常。从实际的角度来看,这是有道理的,你想要抓住你的“真实”异常,然后如果你愿意,也可以处理未关闭的资源。

但在try-finally中,finally中传播的异常是传播的(而try中的一个被“吞噬”),因此我们可以选择三种不良解决方案:

  1. 颠倒try-finally的逻辑,使其与try-with-resources对齐并破坏代码(或更确切地说,错误)与之前所有代码的兼容性。
  2. 继续传播“close()”异常,并将try异常注册为已抑制,使两个构造彼此不一致。
  3. 只要保持原样。
  4. 主观上我认为3比1或2差,但是否则很容易争论。但我怀疑这是语言开发人员面临的两难选择,他们碰巧选择了选项3。