为什么尝试..最后阻止未将原始异常注册为抑制?

2022-09-01 07:52:48

使用以下代码:

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 中禁止显示的异常的添加,当块本身因异常而失败时,该语言将原始的“main”异常注册为抑制状态难道不是合乎逻辑的吗?目前,我必须手动模拟这个: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


答案 1

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

请看下面的代码:

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

我建议你为此打开一个功能请求,因为我认为这是一个明智的功能。


答案 2

这不是一个权威的答案,但看起来这样的变化要么会破坏兼容性,要么会相互不一致。try-with-resourcestry-finally

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

但是,在其中,引入的异常被传播(而来自的异常被“吞噬”),因此我们可以选择三种糟糕的解决方案:try-finallyfinallytry

  1. 反转逻辑,使其与所有先前代码保持一致并破坏代码(或者更确切地说,错误)的兼容性。try-finallytry-with-resources
  2. 继续传播 “” 异常,将异常注册为抑制,使两个构造彼此不一致。close()try
  3. 只要保持一切原样。

主观上,我认为3比1或2更糟糕,尽管很容易争论其他情况。然而,我怀疑这是语言开发人员面临的一个困境,他们碰巧选择了选项3。


推荐