Does a finally block always get executed in Java?
Considering this code, can I be absolutely sure that the finally block always executes, no matter what something() is?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
A finally block in Java will always execute if it’s reachable, even when there are return statements in the try or catch blocks. In your code example, the finally block will indeed print to the console regardless of whether something() completes normally or throws an exception, because the finally block executes before any return statement is completed.
Contents
- Understanding Finally Block Execution
- Return Statements and Finally Blocks
- Exception Scenarios
- Edge Cases and Limitations
- Best Practices
- Practical Examples
Understanding Finally Block Execution
The finally block in Java is designed to provide a mechanism for executing code that must run regardless of whether an exception occurs or not. This is particularly useful for resource cleanup operations like closing database connections, file handles, or releasing other system resources.
The Java Language Specification mandates that a finally block is executed if it is reachable. In your code example, the finally block will always execute because there are no conditions that would prevent it from being reached. The only scenarios where a finally block might not execute are:
- The JVM terminates abruptly (such as with
System.exit()) - The JVM crashes
- The thread executing the code is killed
- There’s an infinite loop that prevents the finally block from being reached
Return Statements and Finally Blocks
When a return statement is encountered in a try block, the JVM doesn’t immediately return. Instead, it executes the finally block before completing the return operation. This means that in your code:
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
The sequence of execution would be:
something()is called- If
something()completes normally, the JVM prepares to returnsuccess, but first executes the finally block - If
something()throws an exception, the catch block executes, prepares to returnfailure, but first executes the finally block
Important Note: The return value is determined before the finally block executes, but the actual return happens after the finally block completes.
Exception Scenarios
The finally block behavior is consistent across different exception scenarios:
- Normal execution: When no exception occurs, the finally block executes before the return statement
- Exception caught: When an exception is caught by the catch block, the finally block executes before the catch block’s return statement
- Exception not caught: If the exception is not caught by this try-catch block, the finally block still executes before the exception propagates up the call stack
try {
something();
return success;
}
catch (RuntimeException e) {
return failure;
}
catch (Exception e) {
return otherFailure;
}
finally {
System.out.println("This always prints");
}
In this more complex example, the finally block would execute regardless of which catch block handles the exception, or if no exception occurs.
Edge Cases and Limitations
While finally blocks are very reliable, there are some edge cases to be aware of:
System.exit() Considerations
When System.exit() is called, the JVM begins shutdown procedures. If called from within a try or finally block, the finally block may not complete execution if the shutdown is too abrupt.
try {
System.exit(0);
} finally {
System.out.println("This may not print");
}
Infinite Loops
If there’s an infinite loop in the try block that never completes, the finally block will never be reached:
try {
while(true) {
// infinite loop
}
} finally {
System.out.println("This will never execute");
}
Thread Termination
If the executing thread is terminated abruptly (using Thread.stop() which is deprecated), the finally block may not execute.
Best Practices
When using finally blocks, consider these best practices:
- Keep finally blocks simple: Avoid complex logic or operations that might throw exceptions
- Use for resource cleanup: Finally blocks are ideal for closing resources like database connections, file streams, and network sockets
- Avoid return statements in finally blocks: This can make code flow difficult to understand and may hide exceptions
- Consider try-with-resources: For resources that implement AutoCloseable, prefer try-with-resources syntax over finally blocks
Practical Examples
Resource Management Example
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
// process file
} catch (IOException e) {
// handle exception
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
// handle close exception
}
}
}
Method Return Example
public String processData() {
try {
// complex processing
return "Success";
} catch (Exception e) {
return "Failed";
} finally {
// cleanup operations
System.out.println("Processing complete");
}
}
In this method, regardless of whether the processing succeeds or fails, the “Processing complete” message will always be printed, and the appropriate return value (“Success” or “Failed”) will be returned.
Sources
- Java Language Specification - The try Statement
- Oracle Java Tutorials - The try Statement
- Effective Java - Item 9: Prefer try-with-resources to try-finally
Conclusion
- The finally block in your code example will always execute if it’s reachable, which it is in this case
- Return statements in try or catch blocks do not prevent finally block execution - the finally block runs before the return is completed
- Finally blocks are essential for proper resource management and cleanup operations
- While finally blocks are very reliable, they have some edge cases where they might not execute, such as with
System.exit()or infinite loops - For modern Java development, consider using try-with-resources for resource management instead of traditional finally blocks where appropriate
You can be absolutely sure that in your specific code example, the finally block will execute and print to the console, regardless of what something() does, as long as the JVM continues running normally.