Multiple return statements without compiler error

4.3k views Asked by At

This was an interview question:

public class Demo {

    public static void main(String[] args) {
        System.out.println(foo());
    }

    static String foo() {
        try {
            return "try ...";
        } catch (Exception e) {
            return "catch ...";
        } finally {
            return "finally ..."; //got as result
        }
    }
}

My question is why there are no compile time errors. When I have the return statement in my finally block, it is bound to return from finally instead of try and catch block. I tried to compile this code with -Xlint option, it gives a warning as.

warning: [finally] finally clause cannot complete normally
8

There are 8 answers

0
Hoopje On BEST ANSWER

It does not give a compilation error because it is allowed by the Java Language Specification. However, it gives a warning message because including a return statement in the finally block is usually a bad idea.

What happens in your example is the following. The return statement in the try block is executed. However, the finally block must always be executed so it is executed after the catch block finishes. The return statement occurring there overwrites the result of the previous return statement, and so the method returns the second result.

Similarly a finally block usually should not throw an exception. That's why the warning says that the finally block should complete normally, that is, without return or throwing an exception.

4
Aakash On

There are no compile time error since only 1 and exactly 1 of return statement will actually return the control back to calling code.

As explained @Hoopje, return within try or catch will execute first, their respective return statement will also execute. But just before returning the control back to calling code, it will execute the finally block. Now, this block also returns something, so this return overrides the previous one.

0
Dragan Bozanovic On

This is described in the Java Language Specification:

§14.17

Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.

§14.20.2

If execution of the try block completes normally, then the finally block is executed, and then there is a choice:

  • If the finally block completes normally, then the try statement completes normally.
  • If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S.

If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and 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).
0
thanuja On

Your code works fine because there is only one return statement in try, catch and finally blocks. Compilation error will occur if you try to write two return statements inside one of try, catch or finally blocks saying there is an unreachable return statement.

0
Jens Timmerman On

try running this:

it will print: 1, 2, 3 and then throw a division by zero Exception

public class Demo {
  public static void main(String[] args) {
    System.out.println(foo());
  }
  public static String print(int a){
    System.out.println(a);
    return String.valueOf(a/0);
  }
  static String foo() {
    try {
      return print(1);
    } catch (Exception e) {
      return print(2);
    } finally {
      return  print(3);
    }
  }
}
0
Lasitha Benaragama On

Brilliant Question.. According to my knowledge return statement of the try and catch block is transferred to finally if you have added finally block to your code. That's how its work.

So in this case all code lines are executing and you can try debugging. The all three blocks I tried below code.

public class Main {

    public static void main(String[] args) {
        System.out.println(foo());
    }
    static String foo() {
        try {
            throw new Exception();
        } catch (Exception e) {
            return "catch ...";
        } finally {
            return "finally ..."; //got as result
        }
    }
}

You can get the idea from below link. Multiple returns: Which one sets the final return value?

0
Roel Strolenberg On

It's essentially the same as this:

public boolean someMethod(){
        if(1 == 1){
            return true;
        }
        return false;
}

It will not give a compilation error, although it will give a warning. The compiler will only give an error when there's a chance of no return statement being executed.

0
Tejus Prasad On

(For short answer- Read the bold and italic parts of the answer)

The execution flow as per the Java 8 docs. It provides you the details. You can infer execution of return statements based on the following.

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, then the finally block is executed, and then there is a choice:

– If the finally block completes normally, then the try statement completes normally.

– If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S.

• If execution of the try block completes abruptly because of a throw of a value V, then there is a choice:

– If the run-time type of V is assignment compatible with a catchable exception class of any catch clause of the try statement, then the first (leftmost) such catch clause is selected. The value V is assigned to the parameter of the selected catch clause, and the Block of that catch clause is executed.

Then there is a choice:

› If the catch block completes normally, then the finally block is executed. Then there is a choice:

» If the finally block completes normally, then the try statement completes normally.

» If the finally block completes abruptly for any reason, then the try statement completes abruptly for the same reason.

If the catch block completes abruptly for 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).

– If the run-time type of V is not assignment compatible with a catchable exception class of any catch clause of the try statement, then the finally block is executed.

Then there is a choice:

› If the finally block completes normally, then the try statement completes abruptly because of a throw of the value V.

› If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).

• If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and 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).

the explanation is clear in this link- javaDoc