What is the difference between try-finally and try-catch in Java?

Consider the following two code snippets:

try {
    fooBar();
} finally {
    barFoo();
}

vs.

try {
    fooBar();
} catch (Throwable throwable) {
    barFoo(throwable); // Handles or logs the exception.
}

I prefer the second version since it gives access to the Throwable. Is there any logical difference or preferred convention between these two approaches?

Also, in a try-finally Java block, is there a way to access the exception inside the finally clause?

I’ve worked with Java for quite some time, and your second version (try-catch) is definitely useful because it gives you more control over the exception handling. The big difference here is:

  • try-finally ensures that the finally block will always execute, regardless of whether an exception is thrown or not, but it doesn’t let you inspect or handle the exception itself. It’s purely for cleanup, like closing resources, and the exception is either propagated or ignored.
  • try-catch gives you access to the exception (Throwable). This allows you to log it, modify it, or rethrow it. It’s much more flexible if you need to handle or inspect the exception in any way.

Now, if your primary concern is just ensuring that resources get cleaned up (like closing a file or database connection), try-finally java block is often the better choice. You don’t need to worry about accessing the exception—just making sure cleanup happens is the goal.

You’ve hit on something important, Tim. But here’s where it gets tricky. With try-finally java, you have to be cautious. If an exception is thrown in the finally block itself, it can obscure the original exception thrown in the try block. Here’s an example:

try {
    throw new RuntimeException("Oops!");
} finally {
    throw new IllegalStateException("Another issue!");
}

In this case, the RuntimeException gets swallowed, and only the IllegalStateException is thrown. This can make debugging really difficult, as you’re no longer aware of the original exception.

In such scenarios, try-catch is generally the safer approach because it gives you the ability to log the exception or wrap it in a different exception type before the finally block even executes. So, if exception handling is important to you, I’d lean toward try-catch to ensure you don’t lose critical error information.

Great additions, Alveera! One more thing to consider—performance. If exceptions are rare and your main concern is resource cleanup (like closing files or database connections), a try-finally java block is more lightweight in terms of performance. There’s no need to create an exception object unless an error actually occurs. This can save some overhead, especially in performance-critical applications.

Now, regarding your question: “Can we access the exception inside finally?”

Unfortunately, Java doesn’t let you access the exception directly in the finally block because exceptions bypass the finally unless explicitly caught beforehand. However, you can still work around this limitation. Here’s one way to capture and handle exceptions:

Throwable thrown = null;
try {
    fooBar();
} catch (Throwable t) {
    thrown = t;
} finally {
    if (thrown != null) {
        System.out.println("Caught exception: " + thrown.getMessage());
    }
}

This approach stores the exception and allows you to access it in the finally block. However, if your goal is to handle exceptions properly and not just ensure cleanup, try-catch is still your best bet.