I'd be interested to hear what developers think about the following
issue that has been doing the rounds here at work.
Say we have the following code
public int confused(){
String foo = "bar";
int val = -1;
try{
val = Integer.parseInt(foo);
}
catch(Exception ex){
ex.printStackTrace();
}
finally{
System.out.println("This always executes");
return val;
}
}
The question is:
What do you think about inserting a return within a finally block ?
The language spec appears ambiguous, also different versions of the
compiler behave differently, for example.
Compiling the above with j2se 1.4.1_02-b06 gives no warnings.
Compiling with j2se 1.4.2-b28 gives the following warning
Test.java [38:1] warning: finally clause cannot complete normally
}
^
1 warning
Finished Test.
I've read various articles and specs that seem to indicate that the
jvm handles the stack correctly (in terms of return addresses for
example) but the compiler still raises the warning.
All opinions gratefully accepted
Cheers
Duncan L.Strang
Ryan, calm down, I wasn't suggesting it was the correct way to do
things I was simply asking for opinions ... I guess you are a 'no'
then
Rgds
Duncan
>
I believe, the key here is to question the very motive of returning a value
from a finally block.
<Duncan Strang> wrote in message
news:c0bb40tkqplkvgbie...@4ax.com...
> What do you think about inserting a return within a finally block ?
>
> The language spec appears ambiguous, also different versions of the
> compiler behave differently, for example.
I think that it's legal and unambiguous Java. But the warning might be
justified by code like:
public int moreConfused()
{
try
{
return 22;
}
finally
{
return 33;
}
}
which might not be expected to return 33, but it does.
-- chris
Calm down? I'm fine. And yes, that was a no for the reasons I listed. You
asked for opinions, you got one. I'd consider it acceptable from a logical
point of view. In fact, I was surprised to learn you got a warning from it.
However, the possible cons outweigh the pros considerably, I think.
Section 14.1 of the Language Spec (2nd Ed.) covers normal vs. abrupt
completion of statements in general, section 14.16 discusses all aspects
of the return statement, and section 14.19 discusses all aspects of
try-catch-finally.
Return statements by definition never complete normally, therefore the
compiler warning is valid. Perhaps the question is whether or not it is
useful -- I think it is. As Chris Uppal noted, the behavior of this
construct and similar are well defined. That doesn't mean that their
use is good practice, however. In the first place, implementation bugs
(i.e. compiler / VM bugs in this case) tend to live in little corners
like this, and it's no fun to troubleshoot a failure of your product
that turns out to live in one of those places. More importantly, it is
unwise to write code whose correct interpretation by another human
depends on knowledge of such fine details of the language -- you are
asking for maintenance problems down the road.
The precise construct you provided isn't so bad, but small variations
rapidly become confusing. For instance, what if the try block contains
one or more return statements? Or what if a throwable can go unhandled
by any catch block (e.g. as an OutOfMemoryError would do even in the
sample)? What if the finally block contains statements that might throw
an exception? What if the body of the try statement is long enough that
the presence of a return in the finally block isn't apparent? The
behavior is well defined in all these cases, but its interpretation may
be tricky.
The final nail with respect to the sample code specifically is that the
whole issue can be removed by simply moving the return statement after
the finally block. Behavior would be identical except in the case of a
Throwable other than an Exception being thrown from the try statement,
and arguably you would want to pass something like that on up the call
stack anyway.
Coming back to the compiler warning specifically, I repeat that I think
it useful and appropriate. It is advising you of a dubious programming
practice, hence it is a warning rather than an error. I would heed it.
John Bollinger
jobo...@indiana.edu
I think it is an abomination, which is why I added the warning to javac.
> The language spec appears ambiguous, also different versions of the
> compiler behave differently, for example.
The language spec unambiguously allows it.
> Compiling the above with j2se 1.4.1_02-b06 gives no warnings.
>
> Compiling with j2se 1.4.2-b28 gives the following warning
>
> Test.java [38:1] warning: finally clause cannot complete normally
> }
> ^
> 1 warning
> Finished Test.
Mea culpa. The code for this warning wasn't supposed to go into the product
until 1.5.0. The latest (upcoming) patch for 1.4.2 will remove this warning.
But the warning will definitely be available in 1.5.0, though you'll have to ask
for it (-Xlint or -Xlint:finally). It is a warning, though. The language
allows it, but it is almost always bad style.