Java finally Block

In the last lesson you learned about the Java try-catch block. When you open a file or a connection, you must close it again, even if an error happens halfway through. Java has a clean answer for code that must always run: the finally block.

🤔 Why do we need finally?

Imagine you open a file, then start reading it. Here is the trouble:

  • If reading throws an error, Java stops the try and jumps to catch.
  • So your close-the-file line in try gets skipped. The file is left open.
  • You copy the close into catch too. Now the same cleanup lives in two places.
  • Change it later and you must remember both spots. Easy to forget one.

Here is the messy version with the close in two separate spots.

try {
openFile();
readFile(); // ❌ if this throws...
closeFile(); // ❌ ...this line is skipped!
} catch (Exception e) {
closeFile(); // ❌ so we repeat it here, ugly and easy to forget
}

What we want is one spot that always runs, success or failure. We drop the cleanup there once and stop worrying. That spot is the finally block.

🧩 What is the finally block?

The finally block goes after try (and after catch, if you have one). The code inside it always runs:

  • It runs when the try finishes with no error.
  • It runs when an exception is thrown and the catch handles it.
  • It runs even when no catch matches and the program is about to crash. Java runs finally first on its way out.

That last point surprises people. Even when your program is failing, Java does not skip finally. That is why it is perfect for cleanup.

This is the full structure.

try {
// risky code that might throw
} catch (Exception e) {
// handle the error, runs only if something throws
} finally {
// ✅ always runs, success or failure
}

🔢 The order things run in

The order is always try first, then catch only if needed, then finally last:

  • No error: try runs, catch is skipped, finally runs, program continues.
  • Error that catch handles: try runs until the throwing line, the rest of try is skipped, catch runs, finally runs, program continues.

So finally runs last in both stories.

💡 Seeing finally always run

Let’s prove it. We run two try blocks. One succeeds, one fails, and we watch finally run in both.

public class Main {
public static void main(String[] args) {
// case 1: no error at all
try {
System.out.println("Trying (no error)");
} finally {
System.out.println("Finally ran"); // ✅ runs after a clean try
}
// case 2: an error that gets caught
try {
System.out.println("Trying (with error)");
int x = 10 / 0; // ❌ throws ArithmeticException
System.out.println("This line is skipped");
} catch (ArithmeticException e) {
System.out.println("Caught the error");
} finally {
System.out.println("Finally ran again"); // ✅ runs after catch too
}
}
}

Let’s read it:

  • First try: no error, so finally runs and prints “Finally ran”.
  • Second try: the divide by zero throws, the line after it is skipped, Java jumps to catch, and then finally still runs.

Output

Trying (no error)
Finally ran
Trying (with error)
Caught the error
Finally ran again

Notice “This line is skipped” never printed. The error cut the try short. But finally still ran.

🧹 The classic use: cleanup

The real job of finally is releasing things you opened. Think of cleanup as putting things back the way you found them.

Here is the analogy. You borrow a meeting room at work. You might finish calmly, or you might get an urgent call and rush out. Either way, you hand the room key back. The finally block is “always hand the key back”.

Now the code. We open a resource, use it, hit an error, and still close it.

public class Main {
public static void main(String[] args) {
System.out.println("Opening resource...");
try {
System.out.println("Using resource");
int x = 10 / 0; // ❌ pretend the work goes wrong here
} catch (ArithmeticException e) {
System.out.println("Handling error");
} finally {
System.out.println("Closing resource"); // ✅ always closes
}
}
}

The “Closing resource” line runs whether the work succeeded or threw. So the resource is never left open, and the cleanup lives in one place. This is the pain we started with, solved.

Output

Opening resource...
Using resource
Handling error
Closing resource

In real code that line would be scanner.close(), or closing a file or a database connection. The pattern is the same. Open at the top, use inside try, release inside finally.

🚪 The one case where finally does NOT run

There is one honest exception to “always runs”:

  • If the code calls System.exit(...), the whole Java program shuts down at once.
  • There is no “after” for Java to return to.
  • So finally is skipped in that case.

The System.exit(0) below kills the program before finally gets its turn.

public class Main {
public static void main(String[] args) {
try {
System.out.println("In try");
System.exit(0); // ❌ program stops right here
} finally {
System.out.println("This will NOT print"); // skipped
}
}
}

Output

In try

So the full rule is: finally runs in every normal path, but System.exit is a hard stop that skips it.

⛔ Why returning from finally is a bad idea

You can technically write a return inside finally. Please do not:

  • A return in finally wins over whatever the try or catch was going to do.
  • It can swallow the real return value.
  • Worse, it can swallow an exception on its way out, so it just disappears.

This example looks like it returns 1, but it does not. Watch the finally.

public class Main {
static int getValue() {
try {
return 1; // looks like the answer...
} finally {
return 2; // ❌ this overrides it, the method returns 2
}
}
public static void main(String[] args) {
System.out.println(getValue());
}
}

Output

2

The method returns 2, not 1. The return in finally ran last and replaced return 1. If the try had thrown instead, the return would throw that exception away too. Keep returns out of finally.

No returns in finally

A return inside finally runs last and overrides everything else. It can hide the real return value and even hide an exception. Keep finally for cleanup only, never for deciding what the method gives back.

🆕 try-with-resources: an even cleaner way

Modern Java has an upgrade for things that can be closed, called try-with-resources:

  • Declare the resource right inside try(...).
  • Java automatically closes it when the block ends.
  • So you do not even need a finally for it.
  • It works on any AutoCloseable resource: files, scanners, connections.

Here a Scanner is opened in the brackets and closed for you at the end.

import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// ✅ Scanner is opened in the try() and closed automatically
try (Scanner scanner = new Scanner(System.in)) {
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hello, " + name);
} // scanner.close() happens here automatically, no finally needed
}
}

When the block finishes, for any reason, Java calls close() for you. No finally, no manual close line, nothing to forget. That is why it is the preferred way now.

You can open more than one resource in the same try(...). Separate them with a semicolon. Java closes them all, in the reverse order it opened them.

// ✅ two resources, both closed automatically when the block ends
try (Scanner first = new Scanner(System.in);
Scanner second = new Scanner("some text")) {
// use both here
}

When to use which

Use try-with-resources for anything that can be closed, like files, scanners, and connections. Use a plain finally block for other cleanup that is not a closeable resource, like resetting a flag, stopping a timer, or printing a final message.

⚠️ Common Mistakes

A few finally slip-ups that catch people out. Each one shows the wrong way and then the right way.

Returning from inside finally. A return here runs last and quietly overrides the real result, even an exception.

// ❌ wrong: finally decides the return value
static int bad() {
try {
return compute();
} finally {
return 0; // swallows whatever compute() gave back
}
}
// ✅ right: let try/catch own the result, finally only cleans up
static int good() {
try {
return compute();
} finally {
cleanUp(); // no return here
}
}

Putting important logic only in finally. The finally block is for cleanup, not for the main work. If a key step lives only there, your code becomes hard to follow and easy to break.

// ❌ wrong: the real work is hidden in finally
try {
checkInput();
} finally {
saveToDatabase(); // this is main logic, it does not belong here
}
// ✅ right: main work in try, only cleanup in finally
try {
checkInput();
saveToDatabase();
} finally {
closeConnection(); // cleanup only
}

Not closing resources at all, or closing them by hand when you do not need to. If a resource is closeable, do not write fragile manual close code. Let try-with-resources handle it.

// ❌ wrong: easy to forget the close, and clutters the code
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
// ...and we forgot scanner.close()
// ✅ right: try-with-resources closes it for you
try (Scanner scanner = new Scanner(System.in)) {
String name = scanner.nextLine();
}

✅ Best Practices

Habits that keep finally working for you instead of against you.

  • Prefer try-with-resources for closeable resources. It closes files, scanners, and connections automatically, so there is nothing to forget.
  • Use a plain finally for cleanup that is not a closeable resource. Resetting a flag, stopping a timer, printing a final message.
  • Never put a return inside finally. It can hide the real return value and even hide an exception.
  • Keep finally short and about cleanup only. No heavy logic, no main work, just releasing what you opened.
  • Remember System.exit skips finally. If you call it, do your cleanup before that call, not in the finally.

🧩 What You’ve Learned

Nicely done. Let’s recap finally in clear points.

  • ✅ The finally block always runs after try/catch, whether or not an exception happened.
  • ✅ The order is try → catch (only if needed) → finally, every time.
  • ✅ Its main use is cleanup: closing files, connections, or releasing resources, all in one place.
  • ✅ It runs on success, on a caught exception, and even on an uncaught one. The one thing that skips it is System.exit.
  • Never return from finally, because it can override the real return and swallow an exception.
  • try-with-resources (try(...)) closes closeable resources automatically, and often replaces finally entirely.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    When does the finally block run?

    Why: finally always runs after try/catch, regardless of success or failure.

  2. 2

    What is the main purpose of finally?

    Why: finally is for cleanup that must always happen, such as releasing resources.

  3. 3

    What does try-with-resources do?

    Why: A resource declared in try(...) is closed automatically, so you do not need a finally for it.

  4. 4

    Why should you avoid returning from a finally block?

    Why: A return in finally can hide the try block's return value or its exception, causing subtle bugs.

🚀 What’s Next?

You now have finally for cleanup, but modern Java has an even cleaner way to handle closeable resources. It declares them right in the try and closes them for you automatically. Let’s learn it.

Java try-with-resources

Share & Connect