ZeroToSky
Java Tutorial 72 of 143
Basics
  • Introduction
  • Download and Install Java
  • Download and Install IntelliJ IDEA, Eclipse
  • Creating First Java Application in IntelliJ IDEA
  • JDK vs JRE vs JVM
  • Print output
  • Taking Input
  • Identifiers
  • Keywords
  • Variables
  • Data Types
  • Literals
  • Wrapper Classes
  • Operators
  • Decision Making
  • Loops and Jump Statements
  • Project: Number Guessing Game

All 17 lessons →

Methods
  • Introduction
  • Static Methods vs Instance Methods
  • Access Modifiers
  • Command Line Arguments
  • Variable Arguments (Varargs)

All 5 lessons →

Arrays
  • Introduction
  • One Dimensional Arrays
  • Multidimensional Arrays
  • Array Class
  • Arrays Class

All 5 lessons →

Strings
  • Introduction
  • String
  • StringBuffer
  • StringBuilder
  • String Class Methods
  • StringJoiner
  • StringTokenizer

All 7 lessons →

OOP & Interface

All 14 lessons →

Collections
  • Collection class
  • Collection Interface
  • List Interface
  • ArrayList
  • LinkedList
  • Set Interface
  • HashSet
  • LinkedHashSet
  • TreeSet
  • Queue Interface
  • PriorityQueue
  • Deque
  • ArrayDeque
  • Map Interface in Java
  • HashMap
  • LinkedHashMap
  • TreeMap
  • Hashtable
  • Iterator
  • Comparable and Comparator

All 20 lessons →

Exception Handling

All 7 lessons →

Multithreading & Concurrency
  • Introduction
  • Thread Class
  • Runnable Interface
  • Thread Life Cycle
  • Thread Priority
  • Synchronization
  • Inter-Thread Communication
  • Executor Framework
  • Callable and Future
  • Concurrent Collections

All 10 lessons →

Java 8 Features
  • Lambda Expressions
  • Functional Interfaces
  • Method References
  • Stream API
  • Optional Class
  • Default and Static Methods in Interface
  • Date and Time API

All 7 lessons →

Advanced Java Concepts
  • File Handling
  • Serialization and Deserialization
  • Reflection API
  • Annotations
  • Garbage Collection
  • Memory Management
  • JVM Architecture
  • Class Loading
  • Networking
  • Regular Expressions

All 10 lessons →

JDBC
  • Introduction
  • JDBC Driver
  • JDBC Connection
  • Types of Statements in JDBC
  • Transactions
  • ResultSet
  • Metadata
  • Connection Pooling

All 8 lessons →

GUI & Desktop
  • AWT
  • Swing
  • JavaFX

All 3 lessons →

Web & Enterprise
  • Servlets
  • JSP
  • Spring Framework
  • Spring Boot
  • Hibernate
  • REST API Development

All 6 lessons →

Practice Projects
  • Project: Number Guessing Game
  • Project: Banking System
  • Project: Student Management System
  • Project: Library Management System
  • Project: Quiz Application

All 5 lessons →

Quiz and Coding Practice
  • Java Topic-wise Quiz
  • Coding Practice Problems
  • Java Basics Coding Practice Problems
  • Java Exercises

All 4 lessons →

Interview Questions
  • Core Java Interview Questions and Answers
  • Advanced Java Interview Questions and Answers
  • Java Interview Questions

All 3 lessons →

DSA & Competitive Programming
  • Arrays and Strings
  • Linked List
  • Stack
  • Queue
  • Tree
  • Graph
  • Heap
  • Hashing
  • Sorting
  • Searching
  • Dynamic Programming
  • Roadmap for DSA in Java

All 12 lessons →

Java Finally Block

Learn how the Java finally block works, when it executes, how it works with try-catch, resource cleanup, return statements, and try-with-resources.

Gaurav 6 min read Sign in to save
On this page

Java Finally Block

The finally block in Java is used to execute code after a try or try-catch statement finishes. It is commonly used for cleanup operations such as closing resources.

A finally block can be used with try and catch:

try {
    // Code that may throw an exception
}
catch (Exception e) {
    // Handle exception
}
finally {
    // Cleanup code
}

For example:

try {
    int result = 10 / 2;
    System.out.println(result);
}
catch (ArithmeticException e) {
    System.out.println("Arithmetic error");
}
finally {
    System.out.println("Finally block executed");
}

Output:

5
Finally block executed

What Is the Finally Block?

The finally block contains code that is intended to execute after the try and catch processing.

It is commonly used for operations that should happen regardless of whether an exception occurs.

Example:

try {
    System.out.println("Try block");
}
finally {
    System.out.println("Finally block");
}

Output:

Try block
Finally block

Unlike catch, a finally block is not used to handle an exception. Its primary purpose is cleanup or other code that should normally execute after the operation.

Syntax of Finally

The basic syntax is:

try {
    // Code
}
finally {
    // Code that should normally execute afterward
}

A finally block can also be used with catch:

try {
    // Code
}
catch (Exception e) {
    // Handle exception
}
finally {
    // Cleanup
}

Finally Without Catch

A finally block does not always require a catch block.

Example:

try {
    int result = 10 / 2;
    System.out.println(result);
}
finally {
    System.out.println("Cleanup code");
}

Output:

5
Cleanup code

If an exception occurs and there is no catch, the exception propagates after the finally block executes.

Example:

try {
    int result = 10 / 0;
}
finally {
    System.out.println("Finally executed");
}

Output includes:

Finally executed

followed by the uncaught ArithmeticException.

Finally with Try-Catch

The most common form combines all three blocks:

try {
    // Risky code
}
catch (Exception e) {
    // Exception handling
}
finally {
    // Cleanup
}

Example:

try {
    int result = 10 / 0;
}
catch (ArithmeticException e) {
    System.out.println("Cannot divide by zero");
}
finally {
    System.out.println("Execution completed");
}

Output:

Cannot divide by zero
Execution completed

The catch block handles the exception, and the finally block then executes.

When No Exception Occurs

If the try block completes successfully, the catch block is skipped and the finally block executes.

Example:

try {
    int result = 10 / 2;
    System.out.println(result);
}
catch (ArithmeticException e) {
    System.out.println("Arithmetic error");
}
finally {
    System.out.println("Finally executed");
}

Output:

5
Finally executed

Execution flow:

try
 ↓
No exception
 ↓
Skip catch
 ↓
finally

When an Exception Occurs

If an exception occurs inside the try block:

  1. Java stops executing the remaining statements in the try block.
  2. Java searches for a matching catch.
  3. The matching catch executes if found.
  4. The finally block executes.
  5. Execution continues after the entire statement, or the exception propagates if it remains unhandled.

Example:

try {
    System.out.println("Before exception");

    int result = 10 / 0;

    System.out.println("After exception");
}
catch (ArithmeticException e) {
    System.out.println("Exception handled");
}
finally {
    System.out.println("Finally executed");
}

Output:

Before exception
Exception handled
Finally executed

The "After exception" statement is never executed.

Finally for Resource Cleanup

One traditional use of finally is closing resources.

For example:

FileReader reader = null;

try {
    reader = new FileReader("data.txt");

    // Read the file
}
catch (IOException e) {
    System.out.println("File operation failed");
}
finally {
    if (reader != null) {
        try {
            reader.close();
        }
        catch (IOException e) {
            System.out.println("Unable to close file");
        }
    }
}

The finally block provides an opportunity to close the resource even when an exception occurs.

However, for resources that implement AutoCloseable, modern Java code should generally prefer try-with-resources.

Finally vs Try-With-Resources

Try-with-resources automatically closes resources after the try block finishes.

Instead of:

FileReader reader = null;

try {
    reader = new FileReader("data.txt");
}
catch (IOException e) {
    System.out.println("File error");
}
finally {
    if (reader != null) {
        try {
            reader.close();
        }
        catch (IOException e) {
            System.out.println("Close failed");
        }
    }
}

you can use:

try (FileReader reader = new FileReader("data.txt")) {
    // Use reader
}
catch (IOException e) {
    System.out.println("File error");
}

Try-with-resources is generally simpler and handles resource closure automatically.

Finally and Return Statements

A finally block normally executes even when a return statement appears in the try or catch block.

Example:

static int getNumber() {

    try {
        return 10;
    }
    finally {
        System.out.println("Finally executed");
    }
}

Calling:

System.out.println(getNumber());

Output:

Finally executed
10

The finally block executes before the method returns.

Return from Finally

Although Java permits a return statement inside finally, it is strongly discouraged because it can override a return value or suppress an exception.

Example:

static int getNumber() {

    try {
        return 10;
    }
    finally {
        return 20;
    }
}

The method returns:

20

The return from finally overrides the return from try.

Because this can make program behavior difficult to understand and can hide exceptions, avoid returning from finally.

Finally Can Override an Exception

A return in finally can even suppress an exception.

Example:

static int calculate() {

    try {
        throw new RuntimeException("Something went wrong");
    }
    finally {
        return 10;
    }
}

The method returns 10, and the exception is suppressed.

This is one reason why returning from finally should be avoided.

Finally and Exceptions in Catch

A finally block executes after a matching catch block.

Example:

try {
    int result = 10 / 0;
}
catch (ArithmeticException e) {
    System.out.println("Exception handled");
}
finally {
    System.out.println("Cleanup");
}

Output:

Exception handled
Cleanup

If the catch block itself throws another exception, the finally block still executes before that exception propagates.

try {
    int result = 10 / 0;
}
catch (ArithmeticException e) {
    System.out.println("Handling exception");
    throw new RuntimeException("New exception");
}
finally {
    System.out.println("Finally executed");
}

Output includes:

Handling exception
Finally executed

The new exception then propagates to the caller.

Finally with Nested Try-Catch

A nested try-catch-finally structure can have multiple finally blocks.

Example:

try {

    try {

        int result = 10 / 0;

    }
    catch (ArithmeticException e) {

        System.out.println("Inner catch");

    }
    finally {

        System.out.println("Inner finally");
    }

}
catch (Exception e) {

    System.out.println("Outer catch");

}
finally {

    System.out.println("Outer finally");
}

Output:

Inner catch
Inner finally
Outer finally

Each finally block executes according to the flow of its associated try statement.

Finally and System.exit()

There is an important exception to the normal execution behavior of finally.

If the JVM is terminated using System.exit(), normal finally execution does not occur.

Example:

try {
    System.out.println("Try block");

    System.exit(0);
}
finally {
    System.out.println("Finally block");
}

The JVM terminates before the finally block can execute normally.

Therefore, finally should not be treated as an absolute guarantee under every possible termination condition.

When Does Finally Not Execute?

In normal Java execution, finally executes after the associated try/catch processing.

However, there are exceptional situations where it may not execute, such as:

  • System.exit() terminates the JVM.
  • The JVM terminates abnormally.
  • The process is forcibly terminated.
  • The operating system or runtime environment stops execution.

Therefore, saying that finally always executes is not strictly correct.

A more accurate statement is that finally normally executes when control leaves the associated try/catch statement.

Finally Execution Flow

Case 1: No Exception

try
 ↓
No exception
 ↓
finally
 ↓
Continue

Case 2: Exception Handled

try
 ↓
Exception
 ↓
catch
 ↓
finally
 ↓
Continue

Case 3: Exception Not Handled

try
 ↓
Exception
 ↓
No matching catch
 ↓
finally
 ↓
Exception propagates

Case 4: Return in Try

try
 ↓
return
 ↓
finally
 ↓
Method returns

The finally block runs before the method actually returns.

Finally with Loops

A finally block also executes when control leaves a try statement because of a break or continue.

Example:

for (int i = 0; i < 3; i++) {

    try {
        if (i == 1) {
            break;
        }

        System.out.println(i);
    }
    finally {
        System.out.println("Finally");
    }
}

Output:

0
Finally
Finally

When break leaves the loop, the finally block associated with the current try still executes.

Finally and continue

Example:

for (int i = 0; i < 3; i++) {

    try {

        if (i == 1) {
            continue;
        }

        System.out.println(i);

    }
    finally {

        System.out.println("Finally");
    }
}

Output:

0
Finally
Finally
2
Finally

The finally block executes before the continue takes effect.

Common Uses of Finally

The finally block can be useful for:

  • Closing legacy resources
  • Releasing locks
  • Restoring temporary state
  • Cleaning up temporary objects
  • Performing operations that should normally happen after a try statement

For example:

Lock lock = getLock();

try {
    lock.lock();
    // Critical section
}
finally {
    lock.unlock();
}

The finally block ensures that the lock-release operation is attempted when control leaves the try block.

Common Mistakes

Returning from Finally

Avoid:

try {
    return 10;
}
finally {
    return 20;
}

The finally return overrides the earlier return and can make the code confusing.

Throwing a New Exception Without Considering the Original

Be careful when throwing another exception from finally, because it can replace an exception that was already propagating.

For example:

try {
    throw new RuntimeException("Original");
}
finally {
    throw new RuntimeException("New");
}

The new exception can obscure the original failure.

Using Finally When Try-With-Resources Is Better

For AutoCloseable resources, prefer:

try (FileReader reader = new FileReader("data.txt")) {
    // Use resource
}

rather than manually managing the resource with finally.

Finally vs Catch

finally catch
Used primarily for cleanup or post-processing Used to handle an exception
Normally executes after try/catch processing Executes only when its exception type matches
Does not receive an exception automatically Receives the exception object
Can be used without catch Must be associated with a try
Commonly used for cleanup Commonly used for recovery or error handling

Finally vs Try-With-Resources

Finally Try-With-Resources
General-purpose cleanup mechanism Designed specifically for resource management
Cleanup code is written manually Resources are closed automatically
Can become verbose Usually concise
Useful for general cleanup Best suited for AutoCloseable resources

Key Points to Remember

  • finally is used with try and optionally catch.
  • It normally executes when control leaves the associated try statement.
  • It can execute whether an exception occurs or not.
  • It can be used without a catch block.
  • It is commonly associated with cleanup operations.
  • finally normally executes before a method returns.
  • Avoid using return inside finally.
  • An exception thrown from finally can replace an exception that was already propagating.
  • System.exit() prevents normal finally execution.
  • Try-with-resources is generally preferred for closing AutoCloseable resources.
  • finally and catch have different purposes: catch handles exceptions, while finally is primarily for cleanup or post-processing.

Conclusion

The finally block in Java provides a mechanism for executing cleanup or post-processing code after a try statement. It normally runs whether the operation succeeds, an exception is handled, or an exception propagates.

Although finally remains useful for general cleanup, modern Java applications should generally use try-with-resources for managing files, streams, database resources, and other objects that implement AutoCloseable.

Avoid placing return or unnecessary exception-throwing logic inside finally, because doing so can override normal control flow and make errors harder to diagnose.

Related

Found a problem on this page, or something that could be clearer?

Goes straight to the author. Not published anywhere.