為什么try..finally阻止不將原始異常注冊為抑制?

[英]Why does try..finally block not register the original exception as suppressed?


With the following code:

使用以下代碼:

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

I get this result:

我得到這個結果:

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

However, with the addition of suppressed exceptions in Java 7, wouldn't it be logical for the language to register original "main" exception as suppressed when finally block itself fails with exception? Currently I have to manually emulate this:

但是,通過在Java 7中添加抑制的異常,當最終塊本身因異常而失敗時,將原始“主”異常注冊為抑制的語言是否合乎邏輯?目前我必須手動模擬這個:

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

to receive more useful (for understanding what's going on) result:

獲得更多有用的(用於了解正在發生的事情)結果:

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)

EDIT: To clarify what I'm wondering. Current Java version is 8, suppressed exceptions are not a brand new feature. But try..finally still doesn't incorporate them. Is there something that prevents this from happening?

編輯:澄清我在想什么。目前的Java版本是8,抑制異常不是一個全新的功能。但是試試..最后仍然沒有加入它們。有什么東西阻止這種情況發生嗎?

2 个解决方案

#1


8  

Because try-with-resources is syntactic sugar and the Java compiler doesn't expand regular try-finally blocks in the same way.

因為try-with-resources是語法糖,Java編譯器不會以相同的方式擴展常規的try-finally塊。

Take a look at the following code:

看一下下面的代碼:

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

When compiled and then decompiled (using IntelliJ IDEA) it looks like this:

編譯然后反編譯(使用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();
        }
    }
}

Whereas this code:

而這段代碼:

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

Looks exactly the same when compiled and decompiled.

編譯和反編譯時看起來完全相同。

Now, the case could definitely be made that all finally blocks should be expanded in the same way as is done above, but for some reason that has either been overlooked or decided against.

現在,絕對可以確保所有最終塊都應該以與上面相同的方式進行擴展,但由於某些原因,這些塊被忽略或決定反對。

I suggest you open a feature request for this because I think it's a sensible feature.

我建議你打開一個功能請求,因為我認為這是一個明智的功能。

#2


5  

This isn't an authoritative answer but it looks like such a change would either break compatibility, or try-with-resources and try-finally would be inconsistent with each other.

這不是一個權威性的答案,但看起來這樣的改變會破壞兼容性,或者嘗試使用資源和try-finally會彼此不一致。

The semantics in try-with-resources is that the exception thrown from the try block is propagated, with the exception thrown when invoking the close() method registered as suppressed. This makes sense from a practical point of view, you want to catch your "real" exception and then maybe also deal with the resource not closing if you want to.

try-with-resources中的語義是傳播try塊拋出的異常,並在調用注冊為suppress的close()方法時拋出異常。從實際的角度來看,這是有道理的,您希望捕獲“真正的”異常,然后如果您願意,也可以處理未關閉的資源。

But in try-finally it is the exception thrown in finally that is propagated (while the one from try is "swallowed") and therefore we have a choice of three bad solutions:

但是在try-finally中,最終拋出的異常被傳播(而try中的那個被“吞噬”),因此我們可以選擇三種不好的解決方案:

  1. Reverse the logic of try-finally to align it with try-with-resources and ruin code (or rather, bug) compatibility with all previous code.
  2. 顛倒try-finally的邏輯,使其與try-with-resources和破壞代碼(或者更確切地說,bug)兼容所有以前的代碼。

  3. Keep propagating the "close()" exception with the try exception registered as suppressed, making the two constructs inconsistent with each other.
  4. 繼續傳播“close()”異常,並將try異常注冊為suppress,使兩個構造彼此不一致。

  5. Just leave everything as it is.
  6. 只要保持原樣。

Subjectively I see 3 as less bad than 1 or 2, though it's fairly easy to argue otherwise. I suspect however that this was a dilemma the language developers were faced with and they happened to choose option 3.

主觀上我認為3比1或2差,但是否則很容易爭論。但我懷疑這是語言開發人員面臨的兩難選擇,他們碰巧選擇了選項3。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2015/06/19/72018653b02fc4a4b196cf0ad9218229.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com