Exploring the Edge Cases: When the finally Block May Not Execute in Java

Pallavi Devraye
3 min readJun 15, 2024

--

In Java, the finally block is a critical part of exception handling, designed to ensure that a block of code runs regardless of whether an exception occurs. The typical use case for a finally block is to release resources, close connections, or clean up after a try block, which may throw an exception. However, there are some scenarios where the finally block might not execute.

This article explains about the situations where the finally block could potentially be bypassed and examines the mechanisms behind such behavior. We will explore several examples to provide a comprehensive understanding of these exceptions to the rule.

The Basics of finally in Java

The finally block is associated with a try block and optionally a catch block. Its primary purpose is to execute crucial cleanup code irrespective of whether an exception is thrown or not.

public class FinallyExample {
public static void main(String[] args) {
try {
// Code that may throw an exception
} catch (Exception e) {
// Handling exception
} finally {
// Cleanup code
System.out.println("This will always execute.");
}
}
}

In the example above, the finally block will execute no matter what happens in the try or catch blocks.

Scenarios Where finally May Not Execute

While the finally block is intended to always run, there are a few specific circumstances where it might not:

  1. JVM Termination: If the Java Virtual Machine (JVM) is terminated abruptly (e.g., by calling System.exit()), the finally block will not execute.
public class FinallyExample {
public static void main(String[] args) {
try {
System.out.println("Inside try block");
System.exit(0);
} finally {
// This will not execute
System.out.println("Inside finally block");
}
}
}

In this example, calling System.exit(0) terminates the JVM, and the finally block does not get a chance to execute.

2. Thread Interruption: If the thread executing the try block is interrupted or killed, the finally block might not execute. This is less common in modern Java as explicit thread termination is typically discouraged in favor of more controlled shutdown mechanisms.

public class FinallyExample {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("Inside try block");
Thread.currentThread().stop();
} finally {
// This will not execute
System.out.println("Inside finally block");
}
}
});
thread.start();
}
}

Here, calling Thread.stop() is unsafe and deprecated, but it demonstrates that abrupt termination can bypass the finally block.

3. Power Failure or Hardware Crash: Situations like power failures, hardware crashes, or other catastrophic events can prevent the finally block from executing. These are generally outside the control of the application.

4. Infinite Loops or Blocking Calls: If the try block contains an infinite loop or a blocking call that never returns, the finally block will not execute unless the loop is exited or the blocking call returns.

public class FinallyExample {
public static void main(String[] args) {
try {
while (true) {
// Infinite loop
}
} finally {
// This will not execute
System.out.println("Inside finally block");
}
}
}

This example demonstrates that an infinite loop within the try block will prevent the finally block from executing.

Ensuring Resource Cleanup

To ensure resources are always released properly, especially when dealing with I/O operations, Java 7 introduced the try-with-resources statement. This feature ensures that each resource is closed at the end of the statement, regardless of whether an exception is thrown.

public class TryWithResourcesExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}

In this example, the BufferedReader is automatically closed at the end of the try block, ensuring proper resource cleanup without the need for an explicit finally block.

Conclusion

While the finally block is designed to execute regardless of what happens within the try or catch blocks, certain extreme circumstances can prevent its execution. Understanding these scenarios helps in writing more robust Java applications, especially when dealing with critical resource management.

By using modern constructs like try-with-resources and avoiding deprecated practices such as Thread.stop(), developers can mitigate the risks and ensure that necessary cleanup actions are always performed.

--

--

Pallavi Devraye

Senior Backend Engineer 🚀 | Java, Spring Boot, Kafka, Microservices enthusiast | Crafting robust, scalable solutions | #Java #SpringBoot #Kafka #Microservices