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.