Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

What is the reason why finally block Cannot be executed?

A finally block will not execute due to other conditions like when JVM runs out of memory when our java process is killed forcefully from task manager or console when our machine shuts down due to power failure and deadlock condition in our try block.

What happens if exception occurs in finally block?

If the exception is not handled at the higher level, the application crashes. The "finally" block execution stops at the point where the exception is thrown. Irrespective of whether there is an exception or not "finally" block is guaranteed to execute. Then the original exception that occurred in the try block is lost.

Do finally block get executed if the exception had not occurred?

A finally block always executes, regardless of whether an exception is thrown.

Does try finally catch exceptions?

Yes, it absolutely will. Assuming your finally block doesn't throw an exception, of course, in which case that will effectively "replace" the one that was originally thrown.


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

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:

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.


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.

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.

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:

  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. Keep propagating the "close()" exception with the try exception registered as suppressed, making the two constructs inconsistent with each other.
  3. Just leave everything as it is.

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.