Chapter 11 - Java for Beginners Course

Return statement in try/catch blocks

By: Andres Perez

When working with try/catch/finally blocks, it’s not always obvious what happens if you place a return statement for the method inside one of the blocks. The behavior of the program will vary depending on the block in which the program returns the value.

The return statement in the try and catch blocks

Even if we return a value from our method inside the try block, the code in the finally block will still run before the value is actually returned. For example, let’s use this class for dividing integers:

public class IntegerDivider {

    int divide(int dividend, int divisor) {
        try {
            System.out.println("Try block executed");
            return dividend/divisor;
        } catch (ArithmeticException e) {
            System.out.println("Catch block executed");
            System.out.println("An ArithmeticException occurred: " + e.getMessage());
            return -1;
        } finally {
            System.out.println("Finally block executed");
        }
    }

}

Also, let’s call our method in the following way:

IntegerDivider divider = new IntegerDivider();
// the divisor is not 0, so no exception is thrown
System.out.println("The result is: "  + divider.divide(100,25));

In this case, since the divisor is not 0, no exception occurs in the try block, and the return statement is executed. But, before the result of the division is actually returned, the code inside the finally block will be executed. As a result, the output of the program is:

Try block executed
Finally block executed
The result is: 4

On the other hand, if the divisor is 0, an ArithmeticException occurs and it is caught by the catch block. In this case, the return statement in the try block is not executed. Instead, the catch block is executed and it returns a value of -1. But, as in the previous case, the code inside the finally block will be executed before the -1 is actually returned:

IntegerDivider divider = new IntegerDivider();
// the divisor is 0, so an ArithmeticException is thrown
System.out.println("The result is: "  + divider.divide(100,0));

Output:

Try block executed
Catch block executed
An ArithmeticException occurred: / by zero
Finally block executed
The result is: -1

The return statement in the finally block

As mentioned in previous lessons, the finally block will be executed regardless of what happens in the try and catch blocks. So, if only the finally block has a return statement, it will return that value no matter what happens in the other blocks.

It is also possible that both the try and catch blocks also have return statements. In this case, we will reach the return statement in either the try or the catch block, and then the code in the finally block will be executed.

However, since there is also a return statement in the finally block, this last statement will override the previous one. So, the return statement inside the finally block is the one that counts in the end and determines the value to be returned.

Let’s illustrate this with an example. Assume we have the same method as before for integer division. But this time, it also has a return statement in the finally block:

public class IntegerDivider {

    int divide(int dividend, int divisor) {
        try{
            System.out.println("Try block executed");
            return dividend/divisor;
        } catch (ArithmeticException e) {
            System.out.println("Catch block executed");
            System.out.println("An ArithmeticException occurred: " + e.getMessage());
            return -1;
        } finally {
            System.out.println("Finally block executed");
            // return statement that overrides returns in try and catch
            return 0;
        }
    }

}

Also, let’s call this method using some values so we are able to see what it returns. First, we will choose a divisor different from 0 so that no exception occurs:

IntegerDivider divider = new IntegerDivider();
// the divisor is not 0, so no exception is thrown
System.out.println("The result is: "  + divider.divide(100,25));

Output:

Try block executed
Finally block executed
The result is: 0

As we can see, no exception occurs, so only the try and finally blocks are executed. But instead of returning 25, following the return inside the try block, our method returns 0, as the return statement in the finally block overrides the one in the try block.

Now let’s make the divisor equal to 0, so that an exception occurs in our divide method:

IntegerDivider divider = new IntegerDivider();
// the divisor is 0, so an ArithmeticException is thrown and caught
System.out.println("The result is: "  + divider.divide(100,0));

Output:

Try block executed
Catch block executed
An ArithmeticException occurred: / by zero
Finally block executed
The result is: 0

In this case, an ArithmeticException is caught by the catch block. So, its return statement is reached. But, instead of returning -1 as the catch block indicates, our method yet again returns 0.

Once more, the return statement inside the finally block overrides one in the catch block.

Remember that in Java, if a method has a non-void return type , then it is mandatory that a value is returned. So, if the method has a try/catch/finally block and the finally block doesn’t have a return statement, then it is mandatory that the try and catch blocks both have one.
When a return statement is included in the finally block, it discards any unhandled exceptions and returns the value anyway. So you have to be careful for any exceptions that might occur and that need to be handled properly.

A special case of the return statement in finally blocks

Even though the finally block is executed before actually returning the value, the return statement will keep the value to be returned at the moment the statement was reached.

For example, if we had a variable int x = 5, and have a return x in the try block, even if we change its value inside the finally block with x = 3, the method would still return a value of 5.

In code, our example looks like this:

int returnX() {
    int x = 5;
    try {
        return x;
    } finally {
        x = 3;
    }
}

The method returnX will always return a value of 5, even if the value of the variable x is changed to 3 inside the finally block.