How does return work in try, catch, finally in Java?
Asked Answered
S

8

35

I can't understand exactly how return works in try, catch.

  • If I have try and finally without catch, I can put return inside the try block.
  • If I have try, catch, finally, I can't put return in the try block.
  • If I have a catch block, I must put the return outside of the try, catch, finally blocks.
  • If I delete the catch block and throw Exception, I can put the return inside the try block.

How do they work exactly? Why I can't put the return in the try block?

Code with try, catch, finally

 public int insertUser(UserBean user) {
     int status = 0;

     Connection myConn = null;
     PreparedStatement myStmt = null;

     try {
         // Get database connection
         myConn = dataSource.getConnection();

         // Create SQL query for insert
         String sql = "INSERT INTO user "
                    + "(user_name, name, password) "
                    + "VALUES (?, ?, ?)";

         myStmt = myConn.prepareStatement(sql);

         // Set the parameter values for the student
         myStmt.setString(1, user.getUsername());
         myStmt.setString(2, user.getName());
         myStmt.setString(3, user.getPassword());

         // Execute SQL insert
         myStmt.execute();
     } catch (Exception exc) {
         System.out.println(exc);
     } finally {
         // Clean up JDBC objects
         close(myConn, myStmt, null);
     }

     return status;
 }

Code with try, finally without catch

 public int insertUser(UserBean user) throws Exception {
     int status = 0;

     Connection myConn = null;
     PreparedStatement myStmt = null;

     try {
         // Get database connection
         myConn = dataSource.getConnection();

         // Create SQL query for insert
         String sql = "INSERT INTO user "
                    + "(user_name, name, password) "
                    + "VALUES (?, ?, ?)";

         myStmt = myConn.prepareStatement(sql);

         // Set the parameter values for the student
         myStmt.setString(1, user.getUsername());
         myStmt.setString(2, user.getName());
         myStmt.setString(3, user.getPassword());

         // Execute SQL insert
         myStmt.execute();

         return status;
     } finally {
         // Clean up JDBC objects
         close(myConn, myStmt, null);
     }
 }
Scourge answered 26/6, 2018 at 7:12 Comment(5)
That is why it is a bad design to have return inside try-catch or try-catch-finally. Consider this question as well.Russo
IMO, it's perfectly fine and normal to return in try block, but you need to make sure you also return something in all the catch blocks. Other than that, just take note of what Bathsheba mentioned. This is essentially the same debate on single exit point - whether it is bad to return in an if block.Resentful
@Russo No, it’s patently not bad design. If you return something which is scoped inside the try block, by all means, return from inside try. Do not widen the scope of the variable you want to return. That would be bad design (keep scopes as small as possible).Blate
Possible duplicate of Try-catch-finally-return clarificationHenrieta
@Russo If you don't return from try or catch, it finally statement is useless. That's why it exists, so Java doesn't need goto for cleanup. I can't think of a good reason to return from finally though. I think that was a mistake in the language design to allow that.Navarrete
S
41

Yes, it's confusing.

In Java, all program control paths of a non-void function must finish with a return, or throw an exception. That's the rule put nice and simply.

But, in an abomination, Java allows you to put an extra return in a finally block, which overrides any previously encountered return:

try {
    return foo; // This is evaluated...
} finally {
    return bar; // ...and so is this one, and the previous `return` is discarded
}
Substantial answered 26/6, 2018 at 7:14 Comment(7)
"which overrides any previously encountered return" or throw.Goop
@AndyTurner: Although the second point is not quite so outrageous ;-)Substantial
In my optinion it is indeed an antipattern to throw exceptions from finally clauses, exactly beacuse of that reason.Heeley
@KonradRudolph: Oops. Thank you.Substantial
So you can have try { return something_with_side_effects(); }finally { return bar;} for extra confusion when debugging?! :-DAnis
@Prof.Falken Now I have an urge to try try { return i++; } finally { return i++; } I felt dirty even writing this comment....Immerge
@Substantial Actually I find it quite outrageous to silently swallow exceptions, which is exactly what happens if a previously encountered throw is overridden by a return.Lavonlavona
G
16

Finally block will always execute even if we caught the exception in catch block or even our try block executed as expected.

so when does finally block will be execute with in the flow...

if we have return statement inside the try/catch block then before executing the return statement finally block will be executed (like as for closing the connection or I/O)

function returnType process() {
  try {
      // some other statements
      // before returning someValue, finally block will be executed
      return someValue;
  } catch(Exception ex) {
     // some error logger statements
     // before returning someError, finally block will be executed
     return someError;
  } finally {
    // some connection/IO closing statements
    // if we have return inside the finally block
    // then it will override the return statement of try/catch block
    return overrideTryCatchValue;
  }
}

but if you have return statement inside the finally statement then it will override the return statement inside the try or catch block.

Galatea answered 1/7, 2018 at 5:56 Comment(2)
perfect answer @PrameshBozovich
Hey I think that finally runs after return someValue;. This also makes it easier to remember that finally's return override that of try.Vann
B
12

And if I have try, catch, finally I can't put return in the try block.

You absolutely can. You just need to make sure that every control path in your method is terminated properly. By that I mean: every execution path through your method either ends in a return, or in a throw.

For instance, the following works:

int foo() throws Exception { … }

int bar() throws Exception {
    try {
        final int i = foo();
        return i;
    } catch (Exception e) {
        System.out.println(e);
        throw e;
    } finally {
        System.out.println("finally");
    }
}

Here, you’ve got two possible execution paths:

  1. final int i = foo()
  2. either
    1. System.out.println("finally")
    2. return i
  3. or
    1. System.out.println(e)
    2. System.out.println("finally")
    3. throw e

Path (1, 2) is taken if no exception is thrown by foo. Path (1, 3) is taken if an exception is thrown. Note how, in both cases, the finally block is executed before the method is left.

Blate answered 26/6, 2018 at 10:40 Comment(1)
+1 "You just need to make sure that every control path in your method is terminated properly" technically, the compiler does that for you, sometimes over-zealously.Navarrete
L
0

This is normal program flow when exception handling is involved. Having catch block in the code creates a case where code path can directly jump in to catch block. This defeats the mandate of having return statement in the method which returns something. It is possible that return statement may not get executed if exception occurs, hence compiler throws error. So to avoid this issue, you need at least 1 more return statement in a method.

If you have added a return statement in try-finally block and you dont have catch block, it is ok. There is no case of abnormal code path here.

If you have added a return statement in try block and you have catch block, then you can either add return in catch block or at the end of method.

If you have added a return statement in try block and you have catch block and finally block, then you can either add return in catch block or at the end of method. You can also choose to add return in finally block. If you are using eclipse, it will generate a warning which can be suppressed using below above method definition -

@SuppressWarnings("finally")
Longerich answered 26/6, 2018 at 8:32 Comment(1)
The warning isn't issued by default JDK javac run. It is issued e.g. in Eclipse, if the corresponding preferences checkbox is activated (which is the default case).Acceptable
I
0

Maybe it's clearer if you think of it as an if/else construct:

public Foo bar() {
    if(error == false) {
    } else {}
    if(true) {}
}

This function is not void, so it requires a return statement returning a value of type Foo. This return statement can be at the end. It can as well be inside the if(true) block. Then any return statement after this block would be dead code. But if you put a return statement into the first if block, it is not necessarily executed, so a second one is mandatory, either in the else block, the if(true) block or at the end of the function. Instead of a second return statement, a throw() clause would also do.

The difference with finally is, that the if(true) block is always executed, even if there was a return (or throw) before. If the finally clause contains its own return or throw, it will override any previous return or throw in the try or catch clause.

If the function were of type void, return statements could appear wherever you want (or nowhere)

Iceblink answered 30/11, 2023 at 18:52 Comment(0)
B
-1

I think this is what you're asking:

And if I have try, catch, finally I can't put return in the try block.

So if you add a catch block, you can't put a return in the try block.

The problem is that if you add a catch then control drops through and you need a return at the end of the method or it's a syntax error. I haven't tested this but I assume you could put a return in the try block, but you would also have to add one inside the catch or at then end of the method as you have now.

Breeches answered 26/6, 2018 at 7:18 Comment(4)
You absolutely can put a return in the try block. -1Kamin
Uh, that's what I said. @KaminBreeches
"So if you add a catch block, you can't put a return in the try block." No, it's not what you said.Kamin
"you could put a return in the try block, but you would also have to add one inside the catch or at then end of the method as you have now." I was just pointing out where the OP went wrong. @KaminBreeches
B
-2

In the second example, if the checked exception occurs then it hands over to calling a method.

In the first example, if the checked exception occurs then it handles in the same method, as catch block take the responsibility to handle the exception.

if you write return statement in catch block then it works.
i.e,

try{  
    return ..  
}catch(Exception e){  
    return ..  
}finally{  
}

But it is not good programming practice.

Bodgie answered 26/6, 2018 at 7:54 Comment(1)
“But it is not good programming practice.” — You’ll need to justify that claim. And since I disagree, I’d be very curious about that.Blate
O
-4

When using a public functions other than void functions, you should return something or your function won't.

Olivaolivaceous answered 26/6, 2018 at 12:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.