42

In Java, a try { ... } finally { ... } is executed somewhat unintuitively to me. As illustrated in another question, Does finally always execute in Java?, if you have a return statement in the try block, it will be ignored if a finally block is defined. For example, the function

boolean test () {
    try {
        return true;
    }
    finally {
        return false;
    }
}

will always return false. My question: why is this? Is there a particular philosophy behind this design decision made by Java? I appreciate any insight, thank you.

Edit: I'm particularly interested as to 'why' Java thinks it's ok to violate the semantics that I define. If I 'return' in a try block, the method should return right then and there. But the JVM decides to ignore my instruction and return from a subroutine that actually hasn't yet been reached.

Community
  • 1
  • 1
Travis Webb
  • 14,688
  • 7
  • 55
  • 109
  • 5
    A similar question or interesting thing is that if you have a try-finally without catch, and you throw an exception from finally, then the original exception has gone to nirvana... :) So never ever let exceptions out of finally block – Gábor Lipták Nov 15 '10 at 14:39
  • 3
    No it won't. Your code doesn't compile ;-) – Peter Štibraný Nov 15 '10 at 14:39
  • @Peter: Only because he put in the wrong return type. – Powerlord Nov 15 '10 at 14:47
  • @Gábor: You should maybe throw the Exception from the catch block and append the catched Exception with "throw new Exception("Message", throwable)", where throwable is the catched Exception. This will give you a nice stacktrace later. But if you throw an exception in the finally block this sounds strange, because this would mean that the try block never succeeds ;-) – white_gecko Oct 09 '11 at 23:32
  • 1
    While it looks like a design mistake that "return" statement is permitted in finally, that doesn't mean "Java violated the semantics you defined". The rule is simply that the finally block always gets the last word. It ISN'T "a subroutine that hasn't yet been reached". That is a misunderstanding of the purpose of finally. Finally was added to modern languages precisely because in older languages there was no way to guarantee that certain logic would always be executed "no matter what". It is A Good Thing that the finally "wins" in this case. Move "return false" to AFTER the end of the finally. – ToolmakerSteve Nov 21 '13 at 01:56

7 Answers7

39

Technically speaking, the return in the try block won't be ignored if a finally block is defined, only if that finally block also includes a return.

It's a dubious design decision that was probably a mistake in retrospect (much like references being nullable/mutable by default, and, according to some, checked exceptions). In many ways this behaviour is exactly consistent with the colloquial understanding of what finally means - "no matter what happens beforehand in the try block, always run this code." Hence if you return true from a finally block, the overall effect must always to be to return true, no?

In general, this is seldom a good idiom, and you should use finally blocks liberally for cleaning up/closing resources but rarely if ever return a value from them.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
  • 4
    As I see it Java even warns you if you have a return statement in a finally block. At least Eclipse tells me that "finally block does not complete normally". The finally block is made for closing resources as Andrzej says. – white_gecko Oct 09 '11 at 23:24
  • 1
    Technically speaking, return in the try block ISN'T IGNORED. The return value is set to true. THEN the finally "gets the last say", as it should. Setting the return value to false. Agreed, the spec shouldn't have allowed return in finally, to avoid this confusion. Probably what the programmer meant here, was to put "return false" AFTER THE END of (outside of) the "try/finally" block. – ToolmakerSteve Nov 21 '13 at 02:00
  • This specification is a good design decision. Finally blocks are a DRY design principle. I no longer have to close my db connection before every thrown exception when I can just close it once in a finally block. With that purpose in mind, I'm glad I can optionally swallow any exception in my finally block under specific circumstances so that I don't have to code that circumstance before every thrown exception, or wrap my try/catch/finally blocks in yet another try/catch block. It's only confusing until you learn the rule (just like = vs ==) and it makes upstream logic more concise. – Marcus Pope Jan 24 '14 at 17:25
  • @Marcus - finally blocks are great for that, no doubt about it. The question is whether it's a good idea to (be allowed to) *return a value* from within a `finally` block, and I can't see any good reason to do so. – Andrzej Doyle Jan 24 '14 at 17:27
  • @AndrzejDoyle - I think you missed my point, having a return in a finally block means I can swallow any and all exceptions thrown in all defined catch blocks. Maybe I want to do than when running a test harness, or maybe it should happen when the current day of the week is Sunday, regardless of the circumstance I shouldn't have to code that if-logic before every thrown exception or wrap the whole try block in yet another try catch block because that's not very DRY. – Marcus Pope Jan 24 '14 at 17:36
  • @AndrzejDoyle, thank you for the answer. Beyond your not seeing any reason to allow returning from finally, is there any official word, or research or any (hopefully unbiased) reference that discusses why this might be a bad idea? It would be great if you linked that in. Even a poll of a large portion of the Java community, or blog(s) where some "good" programmers of Java (even a blog from you) would nicely round out this answer, imho. – batbrat Mar 13 '14 at 07:08
2

If code in finally block ends abruptly, it changes return value/exception from try block. This is considered to be bad practice, and you should not do that.

Among other places, this is also discussed in Java Puzzlers book.

Peter Štibraný
  • 32,463
  • 16
  • 90
  • 116
  • How can it be a leftover from C++ when C++ doesn't have finally blocks and doesn't allow throwing (or changing return values of the scope that caused destruction) in destructors which is the closest cousin of finally? – Jacek Sieka Jul 29 '12 at 16:07
  • @JacekSieka: that's an interesting question. My C++ colleague told me that it works the same in C++, so I assumed that Java took that part from c++. I don't know what he meant, maybe just some c++ extension? But if it's not part of official C++, it cannot be leftover ;-) I'll remove that part from my answer. – Peter Štibraný Jul 30 '12 at 22:28
1

If you call javac with -Xlint, then an appropriate warning will be generated indicating that you should not call return from a finally clause. For example (compiling a simple class with the above test() method):

javac -Xlint foo.java
foo.java:13: warning: [finally] finally clause cannot complete normally
    }
^
1 warning
Mike Godin
  • 3,727
  • 3
  • 27
  • 29
1

Purpose of finally:

  • Java people has created finally block for closing operation,which has to be performed in both cases (e.g exception occurred or no exception).

  • It is not recommended to use return statement in finally block as it overrides both the return statement from catch & try block. and warns "finally block does not complete normally"

  • finally block should have return statement only when both try and catch has no return statement.

  • Incase both try and catch have different value then we should not keep anything in finally block,

  • and if we are returning same value in both try and catch block then its better to keep return in finally and remove return in both try & catch block.
  • If finally throws any exception then the return inside that block will not execute.

finally block will not execute only when:

  • On invoke of System.exit()
  • kill process
  • application/environment crashes
  • stackoverflow/infinite loop
TheSprinter
  • 1,523
  • 17
  • 30
0

check this for reference  Does finally always execute in Java?

"A try statement with a finally block is executed by first executing the try block. Then there is a choice:
If execution of the try block completes normally, [...]
If execution of the try block completes abruptly because of a throw of a value V, [...]
If execution of the try block completes abruptly for any other reason R, then the finally block is executed. Then there is a choice:
If the finally block completes normally, then the try statement completes abruptly for reason R.
If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded)."

Community
  • 1
  • 1
Nutan
  • 1,287
  • 11
  • 15
0

the finally construct is a facility provided by the JLS to handle a code prone to some exception. the developer can utilise this facility to ensure a graceful recovery from an exception. to use the finally construct in the manner you've described doesn't make for a good practice. for that matter, it is never good to return anything from the finally block.
so as you asekd, the "philosophy" is to handle any abrupt completion of code. if returning a certain value as part of handling such a state is required, that should be done within the catch block.

anirvan
  • 4,797
  • 4
  • 32
  • 42
-1

Though The finally block is made for closing resources, and a return statement is generally not supposed to be there, and Eclipse warns that "finally block does not complete normally", I found in some circumstances a "finally return" is still desirable.

ResponseType response = new ResponseType();
try{
    //set some properties of the response object.
    response.setStatus(1);
    //return response;
}catch (Exception e){
    //Some other properties of the response object according to the exception.
    response.setStatus(0);
    //return response;
}finally{
    return response;
}

If I don't put the return clause in the finally block, I would have to repeat it in try and catch blocks and the current code is a little clearer.

  • 2
    In this case, I'd rather put the `return` after `finally` (and then delete the empty `finally` block). Much cleaner. – Pang May 19 '14 at 02:40
  • Then if an exception occurs, your return would not run. – Starrow Pan May 20 '14 at 06:35
  • @Starrow Pan: When an uncaught exception is thrown, is there a situation where the method actually returns something? – boumbh Jul 11 '15 at 08:57