Fundamentals 14 min read

Common Pitfalls and Solutions for finally in Java try‑catch‑finally

This article explains several hidden dangers of using finally in Java try‑catch‑finally blocks, such as return statements, code that appears not to execute, execution order with System.err, and cases where finally may be skipped, and provides concrete example code and practical solutions.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Common Pitfalls and Solutions for finally in Java try‑catch‑finally

In Java, try‑catch‑finally looks simple but mastering it is tricky; the finally block, despite its single purpose, hides many pitfalls. Below are several typical problems with code examples and solutions.

Pitfall 1: return in finally

If a return statement appears in finally, it overrides any return value from the try‑catch block, discarding the original result.

① Bad example

public static void main(String[] args) throws FileNotFoundException {
    System.out.println("Result:" + test());
}

private static int test() {
    int num = 0;
    try {
        // num = 1, not returned here
        num++;
        return num;
    } catch (Exception e) {
        // do something
    } finally {
        // num = 2, this value is returned
        num++;
        return num;
    }
}

The execution result shows that the finally return value (2) replaces the try return value.

② Reason analysis

When finally contains a return, the value from try‑catch is discarded, leading to unexpected results.

③ Solution

If a method returns a value, ensure that the return statement appears only once at the end of the method.

④ Correct example

public static void main(String[] args) throws FileNotFoundException {
    System.out.println("Result:" + testAmend());
}

private static int testAmend() {
    int num = 0;
    try {
        num = 1;
    } catch (Exception e) {
        // do something
    } finally {
        // do something
    }
    // ensure return appears only here
    return num;
}

Pitfall 2: Code in finally "does not execute"

A seemingly simple example shows that code after a return in finally may not affect the returned value.

① Bad example

public static void main(String[] args) throws FileNotFoundException {
    System.out.println("Result:" + getValue());
}

private static int getValue() {
    int num = 1;
    try {
        return num;
    } finally {
        num++;
    }
}

The output is 1, not 2, because the finally block increments a local copy that is not the returned value.

② Reason analysis

The finally block runs after the return value has been stored in a temporary variable; the increment does not affect the already‑stored return value.

③ Solution

Do not modify the return value inside finally; keep return statements only at the method end.

④ Correct example

private static int getValueByAmend() {
    int num = 1;
    try {
        // do something
    } catch (Exception e) {
        // do something
    } finally {
        num++;
    }
    return num;
}

Pitfall 3: finally code executes before catch output

When the catch block prints the stack trace (which uses System.err) and finally prints to System.out, the finally output may appear before the catch output because the two streams are independent and may be flushed in parallel.

① Bad example

public static void main(String[] args) throws FileNotFoundException {
    execErr();
}

private static void execErr() {
    try {
        throw new RuntimeException();
    } catch (RuntimeException e) {
        e.printStackTrace();
    } finally {
        System.out.println("Executing finally.");
    }
}

Running this shows the finally message appearing before the stack trace.

② Reason analysis

System.err and System.out are separate streams; they are flushed independently, causing nondeterministic ordering.

③ Solution

Use the same output stream for both catch and finally, e.g., replace e.printStackTrace() with System.out.println(e) or redirect System.err to System.out.

④ Correct example

private static void execErr() {
    try {
        throw new RuntimeException();
    } catch (RuntimeException e) {
        System.out.println(e);
    } finally {
        System.out.println("Executing finally.");
    }
}

Pitfall 4: finally code may not execute at all

Under certain circumstances—such as calling System.exit in the try block, an infinite loop, or JVM crash—the finally block will not run.

① Bad example

public static void main(String[] args) {
    noFinally();
}

private static void noFinally() {
    try {
        System.out.println("I'm try~");
        System.exit(0);
    } catch (Exception e) {
        // do something
    } finally {
        System.out.println("I'm finally~");
    }
}

The output shows that the finally message is never printed.

② Solution

Avoid System.exit (or similar abrupt termination) inside try‑catch; otherwise the finally block will be skipped.

Summary

The article demonstrates several subtle issues with finally in Java, emphasizing that if a method returns a value, the return statement must appear only once at the end of the method to ensure all finally code is executed correctly.

References & Acknowledgements

Alibaba "Java Development Manual"

developer.ibm.com/zh/articles/j-lo-finally

JavaJVMexception handlingfinallyCodetry-catch-finally
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.