Topic 86 of 119 8. Exception Handling in Java Interactive Tutorial

Java Try-With-Resources: Automatic Resource Management via AutoCloseable

10 mins read Last updated: 22 Aug 2026 29,878 views

Direct Answer & Core Concept

When a Java program works with files, database connections, network streams, sockets, or other external resources, those resources usually need to be closed after use.

Java provides try-with-resources to make this process safer and easier. It automatically closes resources when the try block finishes, even when an exception occurs.

This feature works with classes that implement the AutoCloseable or Closeable interface.

Detailed Explanation & Mechanics

What Is Try-With-Resources in Java?

Try-with-resources is a special form of the try statement that allows you to declare resources directly inside the try statement.

Java automatically calls the resource's close() method when execution leaves the block.

Basic syntax

Main.java
Run Online
try(ResourceType resource = new ResourceType()) {
    // Use the resource
}

For example:

Main.java
Run Online
try(FileInputStream input = new FileInputStream("data.txt")) {
    // Read the file
}

You do not need to manually write:

Java handles the closing automatically.


Why Is Resource Management Important?

Resources such as files and database connections are not ordinary Java objects. They may use operating-system or external-system resources.

If they are not closed properly, an application can experience:

  • File descriptor leaks

  • Database connection leaks

  • Memory/resource exhaustion

  • Locked files

  • Network connection problems

  • Reduced application performance

For example, repeatedly opening database connections without closing them can eventually exhaust the available connection pool.

Try-with-resources helps prevent these problems.


Traditional Resource Management Before Try-With-Resources

Before Java 7, developers commonly used a finally block to close resources.

Main.java
Run Online
FileInputStream input = null;
try {
    input = new FileInputStream("data.txt");
    // Read data
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (input != null) {
        try {
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

This works, but it creates a lot of repetitive code.

There are also multiple places where exceptions can occur.


Using Try-With-Resources

The same basic operation can be written much more simply:

Main.java
Run Online
try(FileInputStream input = new FileInputStream("data.txt")) {
    // Read data
} catch (IOException e) {
    e.printStackTrace();
}

When the try block finishes, Java automatically closes input.

This makes the code shorter and reduces the chance of forgetting to close the resource.


How Try-With-Resources Works

Suppose we write:

Main.java
Run Online
try(FileInputStream input = new FileInputStream("data.txt")) {
    // Use input
}

Conceptually, Java ensures that:

is performed when the try block is exited.

This happens whether the block finishes normally or an exception is thrown.

The important idea is:

The resource is automatically closed when execution leaves the try-with-resources statement.


What Is AutoCloseable?

AutoCloseable is a Java interface that defines a close() method.

Its basic form is:

Main.java
Run Online
public interface AutoCloseable {
    void close() throws Exception;
}

A class implementing AutoCloseable can be used as a resource in try-with-resources.

Simple example

Main.java
Run Online
class MyResource implements AutoCloseable {
    public void use() {
        System.out.println("Using resource");
    } @Override public void close() {
        System.out.println("Resource closed");
    }
}

Now it can be used like this:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    resource.use();
}

Output:

Main.java
Run Online
Using resourceResource closed

The close() method is called automatically.


AutoCloseable vs Closeable

Java also provides the Closeable interface.

The relationship is:

Main.java
Run Online
AutoCloseable ↑ Closeable

Closeable extends AutoCloseable.

For example:

Main.java
Run Online
public interface Closeable extends AutoCloseable {
    void close() throws IOException;
}

The main difference is the exception type declared by close().

AutoCloseable can declare:

while Closeable uses:

Many I/O classes implement Closeable.


Simple Custom AutoCloseable Example

You can create your own resource class.

Main.java
Run Online
class DatabaseConnection implements AutoCloseable {
    public void connect() {
        System.out.println("Database connected");
    } public void query() {
        System.out.println("Executing query");
    } @Override public void close() {
        System.out.println("Database connection closed");
    }
}

Use it with try-with-resources:

Main.java
Run Online
public class Main {
    public static void main(String[] args) {
        try(DatabaseConnection db = new DatabaseConnection()) {
            db.connect();
            db.query();
        }
    }
}

Output:

Main.java
Run Online
Database connectedExecuting queryDatabase connection closed

Try-With-Resources and Exceptions

One of the biggest advantages of try-with-resources is that resources are closed even when an exception occurs.

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    System.out.println("Working...");
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Exception occurred");
}

Even though the calculation causes an exception, Java still closes the resource.

The general flow is:

Main.java
Run Online
Create resource↓Enter try block↓Use resource↓Exception occurs↓Resource is closed↓Exception is handled

Multiple Resources in Try-With-Resources

You can manage multiple resources in a single try statement.

Main.java
Run Online
try( FileInputStream input = new FileInputStream("input.txt");
FileOutputStream output = new FileOutputStream("output.txt")) {
    // Copy data
} catch (IOException e) {
    e.printStackTrace();
}

Both resources are automatically closed.


Order of Closing Multiple Resources

When multiple resources are declared, Java closes them in the reverse order of their declaration.

For example:

Main.java
Run Online
try( ResourceA a = new ResourceA();
ResourceB b = new ResourceB();
ResourceC c = new ResourceC()) {
}

The closing order is:

Main.java
Run Online
C.close()B.close()A.close()

This is called LIFO — Last In, First Out.

This ordering is useful when one resource depends on another.


Example of Multiple Resource Closing

Main.java
Run Online
class Resource implements AutoCloseable {
    private String name;
    Resource(String name) {
        this.name = name;
        System.out.println(name + " opened");
    } @Override public void close() {
        System.out.println(name + " closed");
    }
}

Use it:

Main.java
Run Online
try( Resource first = new Resource("First");
Resource second = new Resource("Second");
Resource third = new Resource("Third")) {
    System.out.println("Using resources");
}

Output:

Main.java
Run Online
First openedSecond openedThird openedUsing resourcesThird closedSecond closedFirst closed

Suppressed Exceptions in Try-With-Resources

Sometimes both the main operation and the close() method can throw exceptions.

For example:

Main.java
Run Online
class MyResource implements AutoCloseable {
    @Override public void close() throws Exception {
        throw new Exception("Close failed");
    }
}

And:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    throw new Exception("Main operation failed");
} catch (Exception e) {
    System.out.println(e.getMessage());
}

The exception from the main try operation is the primary exception.

The exception generated while closing the resource becomes a suppressed exception.

You can inspect suppressed exceptions using:

Example:

Main.java
Run Online
catch (Exception e) {
    System.out.println("Main: " + e.getMessage());
    for (Throwable suppressed : e.getSuppressed()) {
        System.out.println("Suppressed: " + suppressed.getMessage());
    }
}

This mechanism prevents the resource-closing exception from hiding the original failure.


Java Try-With-Resources and Finally

Try-with-resources does not mean that finally no longer exists.

You can still use finally when additional cleanup or logic is required.

Example:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    System.out.println("Working");
} finally {
    System.out.println("Finally block executed");
}

The resource is closed as part of the try-with-resources process.

The finally block can then be used for other cleanup logic if necessary.


Using an Existing Resource

Modern Java also allows an already-created resource to be used in try-with-resources if the variable is final or effectively final.

For example:

Main.java
Run Online
FileInputStream input = new FileInputStream("data.txt");
try(input) {
    // Use input
} catch (IOException e) {
    e.printStackTrace();
}

Here, input is effectively final because it is not reassigned.

This feature was introduced in Java 9.


What Does Effectively Final Mean?

A variable is effectively final when it is assigned once and never reassigned.

This is valid:

Main.java
Run Online
FileInputStream input = new FileInputStream("data.txt");
try(input) {
    // Use input
}

But this would not work:

Main.java
Run Online
FileInputStream input = new FileInputStream("data.txt");
input = new FileInputStream("other.txt");
try(input) {
}

Because input has been reassigned, it is not effectively final.


Try-With-Resources with BufferedReader

A common real-world example is reading a text file.

Main.java
Run Online
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Main {
    public static void main(String[] args) {
        try(BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The BufferedReader is automatically closed.

Because the reader wraps another resource, closing the outer reader also handles the underlying stream appropriately.


Try-With-Resources with Database Connections

Try-with-resources is especially useful with JDBC.

Main.java
Run Online
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class Main {
    public static void main(String[] args) {
        String sql = "SELECT id, name FROM users";
        try( Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost/test", "root", "password");
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet result = statement.executeQuery()) {
            while (result.next()) {
                System.out.println(result.getInt("id"));
                System.out.println(result.getString("name"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

The connection, statement, and result set are automatically closed.

This greatly reduces the risk of database resource leaks.


Try-With-Resources with InputStream

For binary files, you can use an input stream.

Main.java
Run Online
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
    public static void main(String[] args) {
        try(FileInputStream input = new FileInputStream("photo.jpg")) {
            int data;
            while ((data = input.read()) != -1) {
                // Process byte
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

When the block finishes, input.close() is automatically called.


Try-With-Resources with OutputStream

You can also safely manage output streams.

Main.java
Run Online
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
    public static void main(String[] args) {
        try(FileOutputStream output = new FileOutputStream("output.txt")) {
            String message = "Hello Java";
            output.write(message.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The output stream is closed automatically.


Creating Your Own Resource Class

Any class can participate in try-with-resources by implementing AutoCloseable.

Main.java
Run Online
class FileProcessor implements AutoCloseable {
    public FileProcessor() {
        System.out.println("Processor started");
    } public void process() {
        System.out.println("Processing file...");
    } @Override public void close() {
        System.out.println("Processor stopped");
    }
}

Then:

Main.java
Run Online
public class Main {
    public static void main(String[] args) {
        try(FileProcessor processor = new FileProcessor()) {
            processor.process();
        }
    }
}

Output:

Main.java
Run Online
Processor startedProcessing file...Processor stopped

This pattern is useful for custom resources such as:

  • API clients

  • Database wrappers

  • Lock managers

  • Temporary resources

  • Network connections

  • File processors


AutoCloseable with Checked Exceptions

An AutoCloseable implementation can declare a checked exception from close().

Main.java
Run Online
class MyResource implements AutoCloseable {
    @Override public void close() throws Exception {
        System.out.println("Closing resource");
    }
}

Therefore, the caller may need to handle or declare the exception.

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    System.out.println("Working");
} catch (Exception e) {
    e.printStackTrace();
}

AutoCloseable with Runtime Exceptions

A resource does not have to declare a checked exception.

Main.java
Run Online
class MyResource implements AutoCloseable {
    @Override public void close() {
        System.out.println("Closed");
    }
}

Then:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    System.out.println("Working");
}

No checked exception handling is required for close() in this example.


Can a Resource Be Null?

Yes.

A null resource does not cause Java to call close() on that resource.

For example:

Main.java
Run Online
MyResource resource = null;
try(resource) {
    System.out.println("Inside try");
}

The important point is that Java cannot call close() on a null reference.


Common Mistake: Manually Closing the Resource

One common mistake is unnecessarily closing a resource inside the try block.

For example:

Main.java
Run Online
try(FileInputStream input = new FileInputStream("data.txt")) {
    // Use input
    input.close();
}

This is usually unnecessary.

The try-with-resources statement already manages the resource.

Prefer:

Main.java
Run Online
try(FileInputStream input = new FileInputStream("data.txt")) {
    // Use input
}

Common Mistake: Closing Only on the Success Path

Without try-with-resources, developers may accidentally close a resource only when the operation succeeds.

For example:

Main.java
Run Online
FileInputStream input = new FileInputStream("data.txt");
process(input);
input.close();

If process() throws an exception, input.close() may never execute.

Try-with-resources avoids this problem:

Main.java
Run Online
try(FileInputStream input = new FileInputStream("data.txt")) {
    process(input);
}

The resource is closed when the try statement exits.


Common Mistake: Catching Everything Unnecessarily

You do not always need a large catch block.

For example:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    resource.use();
} catch (Exception e) {
    e.printStackTrace();
}

In production applications, it is often better to catch specific exceptions and handle them appropriately.

For example:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    resource.use();
} catch (IOException e) {
    System.err.println("Unable to read resource.");
}

The appropriate exception handling depends on the application.


Try-With-Resources vs Finally

FeatureTry-With-ResourcesTraditional finally
Automatic closingYesNo
Code sizeSmallerUsually larger
Exception safetyStrongMore manual
Multiple resourcesEasyMore complex
Resource orderingAutomaticManual
IntroducedJava 7Older Java feature
Recommended for closeable resourcesYesMainly for other cleanup

For resources implementing AutoCloseable, try-with-resources is generally the preferred approach.


Benefits of Try-With-Resources

1. Automatic Cleanup

Resources are closed automatically when the statement finishes.

2. Less Boilerplate

You do not need large finally blocks just to close resources.

3. Better Exception Safety

Resources are closed even when an exception interrupts normal execution.

4. Multiple Resource Support

Several resources can be managed in a single try statement.

5. Suppressed Exception Handling

Java preserves exceptions thrown during resource closing as suppressed exceptions.

6. Cleaner Code

The resource's lifetime is clearly visible directly in the try statement.


When Should You Use Try-With-Resources?

Use try-with-resources whenever you work with a resource that implements AutoCloseable or Closeable.

Typical examples include:

Main.java
Run Online
FileInputStreamFileOutputStreamBufferedReaderBufferedWriterInputStreamOutputStreamSocketDatabase ConnectionPreparedStatementResultSetScanner

Always check the API documentation for the specific resource and its ownership rules.


Best Practices

Prefer Try-With-Resources

For closeable resources, prefer:

Main.java
Run Online
try(Resource resource = createResource()) {
    // Work
}

instead of manually managing close() in finally.

Keep the Resource Scope Small

Open a resource as close as possible to where it is needed.

Main.java
Run Online
try(BufferedReader reader = openFile()) {
    // Only file-related work
}

A smaller scope makes resource ownership easier to understand.

Use Multiple Resources Carefully

If several resources depend on each other, declare them in the correct order so that reverse-order closing is appropriate.

Handle Exceptions Meaningfully

Do not simply ignore exceptions from resource operations.

Main.java
Run Online
catch (IOException e) {
    logger.error("Unable to process file", e);
}

Avoid Unnecessary Manual close()

If try-with-resources owns the resource, normally let it perform the closing.


Try-With-Resources vs Manual Close

Manual approach

Main.java
Run Online
Resource resource = null;
try {
    resource = createResource();
    resource.use();
} finally {
    if (resource != null) {
        resource.close();
    }
}

Modern approach

Main.java
Run Online
try(Resource resource = createResource()) {
    resource.use();
}

The second version is easier to read and less error-prone.


Real-World Example

Imagine a web application that processes uploaded files.

Without proper resource management:

Main.java
Run Online
Upload file↓Open file stream↓Process file↓Exception occurs↓Stream remains open↓Resources accumulate

With try-with-resources:

Main.java
Run Online
Upload file↓Open file stream↓try-with-resources↓Process file↓Success or exception↓Stream automatically closed

This makes resource cleanup much more reliable.


Important Interview Question: What Happens Internally?

Consider:

Main.java
Run Online
try(MyResource resource = new MyResource()) {
    resource.use();
}

Conceptually, Java guarantees that the resource is closed when control leaves the try block.

If an exception occurs during the main operation, Java attempts to close the resource before propagating the exception.

If close() also throws an exception, that closing exception is retained as a suppressed exception associated with the primary exception.

This is one of the major improvements over many manual cleanup patterns.


Java Try-With-Resources Syntax Cheat Sheet

One resource

Main.java
Run Online
try(Resource r = new Resource()) {
    // Work
}

Multiple resources

Main.java
Run Online
try( ResourceA a = new ResourceA();
ResourceB b = new ResourceB()) {
    // Work
}

With catch

Main.java
Run Online
try(Resource r = new Resource()) {
    // Work
} catch (Exception e) {
    // Handle exception
}

With finally

Main.java
Run Online
try(Resource r = new Resource()) {
    // Work
} finally {
    // Additional cleanup
}

Existing effectively-final resource

Main.java
Run Online
Resource r = new Resource();
try(r) {
    // Work
}

Frequently Asked Questions

What is try-with-resources in Java?

Try-with-resources is a Java feature that automatically closes resources after they are used. It works with objects implementing AutoCloseable or Closeable.

Which Java version introduced try-with-resources?

Try-with-resources was introduced in Java 7.

What is AutoCloseable?

AutoCloseable is an interface that defines a close() method. Classes implementing it can be automatically closed by try-with-resources.

What is the difference between AutoCloseable and Closeable?

Closeable extends AutoCloseable. Closeable is commonly used for I/O resources and declares IOException, while AutoCloseable allows a broader Exception declaration.

Does try-with-resources work when an exception occurs?

Yes. The resource is closed when the try-with-resources statement exits, including when an exception occurs.

Can try-with-resources handle multiple resources?

Yes. You can declare multiple resources in the same try statement.

In what order are multiple resources closed?

They are closed in reverse declaration order. The last resource declared is closed first.

What are suppressed exceptions?

If the main operation throws an exception and closing a resource also throws an exception, the closing exception can be stored as a suppressed exception.

Can I create my own AutoCloseable class?

Yes. Implement AutoCloseable and provide the required close() method.

Should I manually call close() inside try-with-resources?

Usually no. The purpose of try-with-resources is to manage the resource automatically.

Graphics and Design Ideas

Graphic 1: Try-With-Resources Lifecycle

Create a simple flow diagram:

Main.java
Run Online
Create Resource↓Try Block↓Use Resource↓Success / Exception↓Automatic close()

Graphic 2: Multiple Resource Closing

Show:

Main.java
Run Online
Resource AResource BResource C↓C closes first↓B closes second↓A closes last

Label it LIFO: Last In, First Out.

Graphic 3: AutoCloseable Relationship

Create a small hierarchy:

Main.java
Run Online
AutoCloseable ↑ Closeable ↑ File I/O Classes

Graphic 4: Manual vs Automatic Cleanup

Two-column visual:

Main.java
Run Online
Manual Cleanup Try-With-Resourcestry try(resource)↓↓use resource use resource↓↓finally automatic close↓close resource

These graphics can make the page easier for beginners to understand and can also improve the visual quality of the tutorial page.

Runnable Code Example: Java Try-With-Resources

Java 17+
Main.java
Run Online
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.IOException;
public class TryWithResourcesDemo {
    public static void main(String[] args) {
        String sampleData = "Line 1: Header\nLine 2: Data Record";
        // Automatically closed upon exiting try block
        try(BufferedReader reader = new BufferedReader(new StringReader(sampleData))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("Read: " + line);
            }
        } catch (IOException e) {
            System.err.println("I/O error: " + e.getMessage());
        }
    }
}

Common Java Technical Interview Questions & Answers

Interview Prep
Q1

What interface must a class implement to be used in a try-with-resources statement?

java.lang.AutoCloseable (or its sub-interface java.io.Closeable).
Q2

How does Try-With-Resources handle suppressed exceptions?

It preserves the primary exception thrown in the try block and appends the close() exception to the primary exception's suppressed exceptions list.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Always use try-with-resources for Streams, Readers, Sockets, and JDBC connections to guarantee zero resource leaks.