Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Learn › Java › Exceptions

Exceptions and finally

When an exception is thrown, which blocks run, and in what order?

When an exception is thrown in the try block, control jumps to the catch block, and the finally block runs whether the try block is left normally, by a return, or by an exception. The order is easy to get wrong when a return is involved or when another exception is thrown inside the catch block.

Checked against real execution · All 32 combinations were run on JDK 21 and checked against the results

Concepts in this lab

finally and try-with-resources
A finally block runs whether the try block ends normally or throws an exception (except when the JVM exits during the try, for example through System.exit()), and it is used to clean up resources. The try-with-resources statement lets you declare a resource that implements AutoCloseable inside the parentheses of try, and close() is then called automatically when the block ends. Compared with closing the resource yourself in finally, it leads to fewer forgotten closes and fewer exception-handling mistakes.
Exception and Error
Both are subtypes of Throwable that represent abnormal situations while a program runs. An Exception is a situation that the application can catch and handle (such as invalid input or a missing file). An Error is a serious problem at the JVM level, such as running out of memory or a stack overflow, and applications usually do not try to recover from it.
Checked and unchecked exceptions
Unchecked exceptions are RuntimeException and its subclasses (in the specification, the Error classes are also unchecked), and the compiler does not check whether they are handled (examples are NullPointerException and IllegalArgumentException). Checked exceptions are all other Exception classes, and the code compiles only if they are handled with catch or declared with throws (examples are IOException and SQLException). By default, Spring's @Transactional rolls back only on RuntimeException and Error, and commits on checked exceptions.

Try these

Running with the default settings

  1. "try start" is printed, and then an IllegalArgumentException is thrown. The remaining lines of the try block ("try end") do not run.
  2. The type of the exception matches the IllegalArgumentException of the catch block. The catch block runs, and the exception is considered handled.
  3. The finally block runs.
  4. The try-catch-finally ends, and the line after it runs. "after the block" is printed, and 2 is returned.

Result of this run

Code

int run() {
    try {
        print("try start");
        if (fail) throw new IllegalArgumentException();  // fail is true
        print("try end");
    } catch (IllegalArgumentException e) {
        print("catch");
    } finally {
        print("finally");
    }
    print("after the block");
    return 2;
}

Assumptions of this model

For all 32 combinations, the code exactly as shown (with only a fail field set to true, print, and Resource added) was compiled and run on JDK 21 on this PC, and the output order and the final result were checked (verify/plain/exflow_code_check.js). Only the case with one resource is covered. When there are several resources, they are closed in the opposite order from the order in which they were opened, and an exception thrown by close() is attached to the original exception as a suppressed exception.

Previous lab: Optional · Next lab: Checked and unchecked exceptions

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these