Improve `finally` block exception handling

David Holmes david.holmes at oracle.com
Mon Apr 18 04:40:58 UTC 2022


Hello,

On 18/04/2022 5:43 am, 
some-java-user-99206970363698485155 at vodafonemail.de wrote:
> 
> Hello,
> 
> are there any plans to improve exception handling in combination with `finally` blocks?

I'm not aware of anything, nor what that anything could realistically 
be. You make only one suggestion that has a little merit.

> Currently, when a `finally` block does not complete normally, the original exception is
> silently discarded (as described in the JLS). This behavior is error-prone, not obvious
> at all, and has been criticized in the past a lot. An example for this is https://stackoverflow.com/q/48088
> and the linked posts there.

The behaviour of try/catch/finally is not "obvious at all", you have to 
read what it means and when you do that you clearly see what happens 
regarding exceptions.

> While javac warns you about this issue when using `-Xlint:finally`, it is only a warning
> and not even enabled by default.
> 
> Are there any plans to forbid usage of `break`, `continue`, `yield` and `return` in
> `finally` blocks?

Why would we do that? What would that gain?

> Switch expressions have already set a precedent for this by not allowing to leave the
> switch expression by something other than a `throw` or `yield` statement, trying to use
> for example a `return` statement causes a compilation error.

That is because it is an _expression_ - expressions have to have 
different language rules to statements. There is no connection to a 
finally block.

> Similarly for `throw` and any implicitly thrown exceptions, is there a plan to at least
> add the original exception as suppressed one to the newly thrown?

That suggestion is not completely without merit, but nor is it a 
"slam-dunk" obvious thing to do. The semantic implications of the 
exceptions matter, and semantics come from the programmers intent. 
There's no reasonable way to automagically determine that when an 
exception is created that another exception (that led to the finally 
block) should be inserted as a "suppressed exception". That would 
actually be completely wrong to do in many circumstances you would 
instead need to act when the exception would terminate the finally block 
and then add the original exception as the "suppressed" exception. But 
really the programmer is in the best position to decide how exceptions 
need to be handled.

> Of course one could argue that the same applies to `catch` clauses whose body accidentally
> causes an exception which discards the caught one. However the main difference is that

Yes exactly the same.

> there, only a specific exception type is caught (and discarded), whereas for `finally`
> exceptions of _any_ type are discarded. It could also be argued that adding suppressed

We have multi-catch now so that argument is somewhat weaker.

> exceptions decreases performance or causes memory leaks, but one the other hand
> this behavior was explicitly included try-with-resources statements, most likely because the
> value this adds was considered more important than any performance issues this
> might cause.

try-with-resources added support for suppressed exceptions because the 
automatic closing of the resource could throw an exception, and that had 
to be factored in to the whole mechanism.

> Also, it is important to keep in mind that this affects _all_ Throwable types, including
> VM errors which you really should not catch, and which due to a `finally` block might
> silently be discarded. Most, if not all, code in which a `finally` does not complete
> normally does not seem to consider this.

That is true. But for me a finally block is intended to be quite small 
and succint and should be written from the perspective of "an unexpected 
exception has occurred, what it is it critical for me to do before 
leaving the current scope".

> This is also not a theoretical problem; this issue exists in multiple open source projects,
> potentially even in the JDK itself.
> Often the code can be rewritten by either moving the complete code or parts of it
> outside of the `finally` block, or by introducing a local variable to hold the result and
> to return that after the `finally` block.
> 
> What do you think about this topic?

I think there is no clear and obvious solution that the language can put 
in place here.

Just my personal 2c.

Cheers,
David

> Is backward compatibility a concern? If so, can you provide an example where using such
> a pattern provides any notable advantages which justify the potential loss of thrown
> VM errors or exceptions.
> 
> Kind regards
> 
> 
> 


More information about the core-libs-dev mailing list