Try with Resources

Learning Objectives

  • Understand the AutoCloseable interface and how it enables automatic resource management in Java
  • Implement try-with-resources statements to replace verbose try-catch-finally patterns
  • Recognize when and why try-with-resources ensures reliable resource cleanup even during exceptions
  • Handle exceptions properly in try-with-resources contexts, including suppressed exceptions
  • Apply try-with-resources to multiple resources and create custom AutoCloseable classes

Introduction

Resource management used to be painful in Java. Open a file, read some data, hit an exception—suddenly your application is leaking file handles. The traditional solution involved nested try-catch-finally blocks that turned simple operations into error-handling mazes.

Java 7 introduced try-with-resources to solve this problem. The try-with-resources statement is a try statement that declares one or more resources and guarantees they'll close automatically. Resources declared in try-with-resources must implement the AutoCloseable interface, and Java ensures they close when the block exits—whether your code succeeds or throws an exception.

This feature fundamentally changed resource management in Java. Instead of writing defensive cleanup code everywhere, you declare your resources in the try statement and the compiler handles the rest. Try-with-resources makes sure resources are closed reliably, even during exception scenarios that used to cause leaks.

The Problem Before Try-with-Resources

Before try-with-resources, proper resource cleanup meant verbose try-catch-finally blocks. Here's what reading a file looked like:

package blog.academy.javapro;

import java.io.*;
import java.util.Scanner;

public class TraditionalApproach {

    // Helper to create test file
    private static void createFile() {
        PrintWriter writer = null;
        try {
            writer = new PrintWriter("data.txt");
            writer.println("Line 1");
            writer.println("Line 2");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

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

        Scanner scanner = null;
        try {
            scanner = new Scanner(new File("data.txt"));
            while (scanner.hasNext()) {
                System.out.println(scanner.nextLine());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }
    }
}

That finally block is necessary but tedious. We need the null check because scanner might not initialize if the constructor fails. This pattern is error-prone—developers often skip the finally block entirely, causing resource leaks in production.

How to Use Try-with-Resources in Java

The try-with-resources statement simplifies everything. Declare your resource in parentheses, and Java closes it automatically:

package blog.academy.javapro;

import java.io.*;
import java.util.Scanner;

public class TryWithResourcesBasic {

    private static void createFile() {
        try (PrintWriter writer = new PrintWriter("data.txt")) {
            writer.println("Line 1");
            writer.println("Line 2");
            writer.println("Line 3");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

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

        try (Scanner scanner = new Scanner(new File("data.txt"))) {
            while (scanner.hasNext()) {
                System.out.println(scanner.nextLine());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

No finally block. No null checks. The Scanner implements AutoCloseable, so try-with-resources handles closing automatically. This is how try-with-resources replaces the traditional and verbose try-catch-finally block—with clean, reliable code.

Using Try-with-Resources with Multiple Resources

Try-with-resources handles multiple resources by separating them with semicolons:

package blog.academy.javapro;

import java.io.*;
import java.util.Scanner;

public class MultipleResources {

    private static void createFile() {
        try (PrintWriter writer = new PrintWriter("input.txt")) {
            writer.println("hello world");
            writer.println("java programming");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

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

        try (Scanner scanner = new Scanner(new File("input.txt"));
             PrintWriter writer = new PrintWriter(new File("output.txt"))) {

            while (scanner.hasNext()) {
                writer.println(scanner.nextLine().toUpperCase());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println("File processing complete!");
    }
}

Resources close in reverse order—writer closes before scanner. This ordering matters when resources depend on each other. Try-with-resources ensures that resources are closed automatically in the correct sequence.

Creating Custom Resources for Try-with-Resources

Any class implementing AutoCloseable works with try-with-resources. Here's a custom resource:

package blog.academy.javapro;

public class MyResource implements AutoCloseable {

    public MyResource() {
        System.out.println("MyResource opened");
    }

    public void doWork() {
        System.out.println("MyResource doing work");
    }

    @Override
    public void close() {
        System.out.println("MyResource closed");
    }

    public static void main(String[] args) {
        try (MyResource resource = new MyResource()) {
            resource.doWork();
        }
    }
}

When the try block exits, close() gets called automatically. Try-with-resources guarantees this happens regardless of how the block exits.

Resource Closing Order in Try-with-Resources

Resources close in reverse order of declaration. First declared, last closed:

package blog.academy.javapro;

public class ResourceFirst implements AutoCloseable {

    public ResourceFirst() {
        System.out.println("ResourceFirst created");
    }

    public void doSomething() {
        System.out.println("ResourceFirst working");
    }

    @Override
    public void close() {
        System.out.println("ResourceFirst closed");
    }
}
package blog.academy.javapro;

public class ResourceSecond implements AutoCloseable {

    public ResourceSecond() {
        System.out.println("ResourceSecond created");
    }

    public void doSomething() {
        System.out.println("ResourceSecond working");
    }

    @Override
    public void close() {
        System.out.println("ResourceSecond closed");
    }
}
package blog.academy.javapro;

public class ClosingOrder {

    public static void main(String[] args) {
        try (ResourceFirst first = new ResourceFirst();
             ResourceSecond second = new ResourceSecond()) {

            first.doSomething();
            second.doSomething();
        }
    }
}

Output:

ResourceFirst created
ResourceSecond created
ResourceFirst working
ResourceSecond working
ResourceSecond closed
ResourceFirst closed

The second resource closes first. This reverse order ensures proper cleanup when resources have dependencies.

Handling Exceptions with Try-with-Resources

Try-with-resources preserves exception information through suppressed exceptions:

package blog.academy.javapro;

public class ResourceWithException implements AutoCloseable {
    private final String name;

    public ResourceWithException(String name) {
        this.name = name;
        System.out.println(name + " opened");
    }

    public void doWork() throws Exception {
        System.out.println(name + " working");
        throw new Exception(name + " work failed");
    }

    @Override
    public void close() throws Exception {
        System.out.println(name + " closing");
        throw new Exception(name + " close failed");
    }

    public static void main(String[] args) {
        try (ResourceWithException resource = new ResourceWithException("MyResource")) {
            resource.doWork();
        } catch (Exception e) {
            System.out.println("\nPrimary exception: " + e.getMessage());

            Throwable[] suppressed = e.getSuppressed();
            if (suppressed.length > 0) {
                System.out.println("Suppressed exceptions:");
                for (Throwable t : suppressed) {
                    System.out.println("  - " + t.getMessage());
                }
            }
        }
    }
}

The work exception is primary. The close exception becomes suppressed. Try-with-resources ensures that resources are closed automatically while preserving all exception details.

Using catch and finally with Try-with-Resources

Try-with-resources blocks can include catch and finally clauses:

package blog.academy.javapro;

import java.io.*;
import java.util.Scanner;

public class CatchAndFinally {

    private static void createFile() {
        try (PrintWriter writer = new PrintWriter("test.txt")) {
            writer.println("Test data");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

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

        try (Scanner scanner = new Scanner(new File("test.txt"))) {
            while (scanner.hasNext()) {
                System.out.println(scanner.nextLine());
            }
        } catch (FileNotFoundException e) {
            System.out.println("Caught: " + e.getMessage());
        } finally {
            System.out.println("Finally block executed");
        }
    }
}

The resource closes before the catch or finally blocks execute. This ordering ensures cleanup happens first.

Java 9 Try-with-Resources: Effectively Final Variables

Before Java 9, you could only use fresh variables in try-with-resources. Java 9 allows effectively final variables:

package blog.academy.javapro;

import java.io.*;
import java.util.Scanner;

public class EffectivelyFinal {

    private static void createFile() {
        try (PrintWriter writer = new PrintWriter("final-test.txt")) {
            writer.println("Java 9 feature");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

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

        // Pre-declared resources
        final Scanner scanner = new Scanner(new File("final-test.txt"));
        PrintWriter writer = new PrintWriter(new File("final-output.txt"));

        // Java 9+: Use them directly
        try (scanner; writer) {
            while (scanner.hasNext()) {
                writer.println(scanner.nextLine());
            }
        }

        System.out.println("Resources closed automatically");
    }
}

The scanner is explicitly final. The writer is effectively final (not reassigned). Both work with try-with-resources in Java 9+.

Try-with-Resources Example: Database Operations

Try-with-resources shines with database code:

package blog.academy.javapro;

import java.sql.*;

public class DatabaseOperations {

    private static void setupDatabase(Connection conn) throws SQLException {
        try (Statement stmt = conn.createStatement()) {
            stmt.execute("CREATE TABLE users (id INT, name VARCHAR(50))");
            stmt.execute("INSERT INTO users VALUES (1, 'Alice')");
            stmt.execute("INSERT INTO users VALUES (2, 'Bob')");
        }
    }

    public static void main(String[] args) {
        try (Connection conn = DriverManager.getConnection("jdbc:h2:mem:testdb")) {
            setupDatabase(conn);

            try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users");
                 ResultSet rs = stmt.executeQuery()) {

                while (rs.next()) {
                    System.out.println("User: " + rs.getString("name"));
                }
            }
        } catch (SQLException e) {
            System.err.println("Database error: " + e.getMessage());
        }
    }
}

Three resources—Connection, PreparedStatement, and ResultSet—all close automatically in the right order. No manual cleanup needed. Try-with-resources makes sure resources are closed reliably even when exceptions occur.

Summary

The try-with-resources statement transformed resource management in Java. It replaces the traditional and verbose try-catch-finally block with concise, reliable code. Resources declared in try-with-resources get closed automatically when the block exits, preventing resource leaks.

Any class implementing AutoCloseable works with try-with-resources. Files, database connections, network sockets—anything needing cleanup can use this pattern. Try-with-resources ensures that resources are closed automatically, even during exceptions.

Multiple resources work seamlessly. Declare them together separated by semicolons, and they close in reverse order. Exception handling is sophisticated—primary exceptions propagate while close exceptions become suppressed, preserving all diagnostic information.

The try-with-resources statement is one of Java's most important features for resource management. It eliminates entire categories of bugs by moving resource cleanup from manual finally blocks to compiler-guaranteed automatic management. Every Java developer should use try-with-resources as their default approach to resource management. It's simpler, safer, and more maintainable than any manual alternative.

Download the full try-with-resources source code.


Ready to master Java? Join our Java Bootcamp to master enterprise-level development, or start with our free Core Java course to build your foundation.

Subscribe and Master Java

If this helped you, you'll love the full Java Program Library4 structured programs with real projects.

$49 /year
Posted in

Get the Java Weekly Digest

Stay sharp with curated Java insights delivered straight to your inbox. Join 5,000+ developers who read our digest to level up their skills.

No spam. Unsubscribe anytime.

Name