File Navigation and I/O ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-10-31

Try-with-resources in Java

The classic try-finally pattern has a hidden flaw: if br.readLine() throws an IOException and then br.close() in the finally block fails as well, only the exception from close() leaves the method — the real cause of the failure disappears without a trace. The try-with-resources statement fixes this problem, together with the problem of a forgotten close() call.

Try-with-resources is a form of the Java try statement (introduced in Java 7) in which resources are declared in parentheses after try and closed automatically: close() is called when the try block exits, both on normal completion and when an exception is thrown. A resource can be any object whose class implements java.lang.AutoCloseable (including its subinterface java.io.Closeable): I/O streams, sockets, JDBC connections, Scanner.

Try-with-resources syntax

A resource is declared and initialised in parentheses right after the try keyword; several resources are separated by semicolons. The catch and finally blocks are optional: if the checked exceptions are declared in the method’s throws clause, a bare try block is enough.

try (ResourceType1 name1 = new ResourceType1(...);
     ResourceType2 name2 = new ResourceType2(...)) {
    // work with the resources
} catch (IOException e) {
    // optional
} finally {
    // optional
}

A resource variable is implicitly final and is visible only inside the try block: it is out of scope in catch and finally, and by then the resource is already closed. If you need a refresher on plain try, catch and finally, see Java Try Catch Finally; its short try-with-resources section is the starting point for this lesson. The formal rules are in JLS §14.20.3.

try-finally vs try-with-resources

Before Java 7 a resource was closed by hand in a finally block; try-with-resources does the same automatically, with less code and more safety: there is no close() call to forget, and an exception from close() no longer overwrites the original one. Compare two versions of a method that reads the first line of a file (imports java.io.*).

Example 1. Closing a resource in finally

public static String readFirstLineWithFinally(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        br.close();
    }
}

A br != null check is not needed here: if the file does not exist, new FileReader(path) throws FileNotFoundException before the try block is entered, and the variable is never assigned.

Now the same method rewritten with try-with-resources.

Example 2. The same method with try-with-resources

public static String readFirstLine(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

// The file a.txt contains the lines "Hello" and "World":
// readFirstLine("a.txt")       -> "Hello"
// readFirstLine("missing.txt") -> java.io.FileNotFoundException
Criterion try-finally try-with-resources
Closing the resource Manually, by calling close() in finally Automatically when the try block exits
Exception from close() Replaces the original exception from try — the cause is lost Attached to the original one as suppressed (getSuppressed())
Several resources Nested try-finally for each resource One pair of parentheses, resources separated by ;, closed in reverse order
Resource requirements Any object with a close method The class must implement AutoCloseable
Java version Any Java 7+; an existing variable as a resource — Java 9+

Multiple resources and closing order

A single try-with-resources statement can declare several resources separated by semicolons; they are opened from left to right and closed in reverse order — the last one opened is closed first. If the constructor of the second resource throws an exception, the first resource, which is already open, is still closed.

Example 3. Two resources in one try

public static String readFirstLine2(String path) throws IOException {
    try (FileReader fr = new FileReader(path);
         BufferedReader br = new BufferedReader(fr)) {
        return br.readLine();
    }
}

br is closed first, then fr. BufferedReader.close() already closes the wrapped FileReader, so the second close() on fr does nothing — this is safe, because closing a Closeable that is already closed must have no effect.

The order is easy to see with a custom resource that prints a message when it is opened and closed.

Example 4. Opening and closing order

public class CloseOrderDemo {

    static class Resource implements AutoCloseable {
        private final String name;

        Resource(String name) {
            this.name = name;
            System.out.println("Opened " + name);
        }

        @Override
        public void close() {
            System.out.println("Closed " + name);
        }
    }

    public static void main(String[] args) {
        try (Resource a = new Resource("A");
             Resource b = new Resource("B")) {
            System.out.println("Working with resources");
        }
    }
}

// Output:
// Opened A
// Opened B
// Working with resources
// Closed B
// Closed A

Note that close() here is declared without throws Exception, so no catch block is required. If close() threw a checked exception, the compiler would demand that you handle it or declare it in throws (the difference between checked and unchecked exceptions is explained in Exceptions in Java).

AutoCloseable vs Closeable: what can be a resource

Only an object whose class implements java.lang.AutoCloseable can be a resource in try-with-resources. java.io.Closeable extends AutoCloseable, so every I/O stream from java.io qualifies automatically. The two interfaces differ in the signature of close() and in what is required from it.

Interface Package and version close() signature Calling close() twice
AutoCloseable java.lang, Java 7 void close() throws Exception May have side effects (idempotence is recommended, not required)
Closeable java.io, Java 5; extends AutoCloseable since Java 7 void close() throws IOException Must have no effect (idempotent)

When you write your own resource, narrow the exception in close(): declare throws IOException, a custom exception class, or no checked exception at all, as in Example 4. Then the calling code does not have to catch a generic Exception. See the AutoCloseable Javadoc for the full contract.

Suppressed exceptions and getSuppressed()

If the try block throws an exception and then close() throws too, the exception from the try block propagates, and the exception from close() is attached to it with addSuppressed(). The suppressed exceptions are returned by Throwable.getSuppressed() as a Throwable[] array (both methods were added to Throwable in Java 7).

Example 5. What does this code print?

public class SuppressedDemo {

    static class FaultyResource implements AutoCloseable {
        @Override
        public void close() {
            throw new IllegalStateException("error in close()");
        }
    }

    public static void main(String[] args) {
        // Option 1: try-finally
        try {
            FaultyResource r = new FaultyResource();
            try {
                throw new RuntimeException("error in try block");
            } finally {
                r.close();
            }
        } catch (RuntimeException e) {
            System.out.println("finally: " + e.getMessage()
                    + ", suppressed: " + e.getSuppressed().length);
        }

        // Option 2: try-with-resources
        try (FaultyResource r = new FaultyResource()) {
            throw new RuntimeException("error in try block");
        } catch (RuntimeException e) {
            System.out.println("try-with-resources: " + e.getMessage());
            for (Throwable s : e.getSuppressed()) {
                System.out.println("  suppressed: " + s.getMessage());
            }
        }
    }
}

// Output:
// finally: error in close(), suppressed: 0
// try-with-resources: error in try block
//   suppressed: error in close()

In the finally version the original exception “error in try block” is gone completely — which is why debugging such code turns into a hunt for an error that “does not exist”. Try-with-resources keeps both errors.

Where to find a suppressed exception

Suppressed exceptions are not logged as separate entries, but e.printStackTrace() and most loggers print them inside the stack trace of the main exception, on a line that starts with Suppressed: .... If the log shows only the “top” error, scroll further down the stack trace.

catch and finally in try-with-resources

In try-with-resources the catch and finally blocks run after all resources have been closed. So you cannot use the resource in catch to “rescue” data, and an exception thrown while closing can be caught by that same catch.

Example 6. Execution order

// Resource is the class from Example 4
try (Resource r = new Resource("R")) {
    throw new IllegalArgumentException("failure");
} catch (IllegalArgumentException e) {
    System.out.println("catch: " + e.getMessage());
} finally {
    System.out.println("finally");
}

// Output:
// Opened R
// Closed R
// catch: failure
// finally

If the exception is thrown while the resource is being created (for example, FileNotFoundException in the FileReader constructor), the body of the try block does not run, there is nothing to close, and control goes straight to the matching catch.

Java 9: a resource declared before try

Since Java 9 the parentheses of try-with-resources can hold an existing variable, as long as it is final or effectively final (nothing is assigned to it after initialisation). In Java 7 and 8 the resource had to be declared inside the parentheses, even if the object already existed.

// Java 7/8: a new variable was required
public static String readFirstLine(BufferedReader reader) throws IOException {
    try (BufferedReader br = reader) {
        return br.readLine();
    }
}

// Java 9+: the variable itself is enough
public static String readFirstLine9(BufferedReader reader) throws IOException {
    try (reader) {
        return reader.readLine();
    }
}

If the variable is reassigned anywhere in the method, try (reader) does not compile: the variable is no longer effectively final. Apart from this change, try-with-resources has behaved the same way in every release since Java 7.

Java version What changed Example
Java 7 try-with-resources, AutoCloseable, addSuppressed() / getSuppressed() introduced try (BufferedReader br = new BufferedReader(...))
Java 8 No changes: the statement works exactly as in Java 7 —
Java 9 A final or effectively final variable can be used as a resource try (reader)
Java 10 var is allowed in a resource declaration (general local variable type inference) try (var br = new BufferedReader(...))
Java 11 – 21 No changes to try-with-resources —

Common mistakes

Most mistakes with try-with-resources come from the scope of the resource variable, from wrapper streams and from resources that should not be closed at all. The table shows what happens in each case and how to fix it.

Mistake What happens How to fix
Reassigning the resource inside try: br = new BufferedReader(...) Compile error: auto-closeable resource br may not be assigned Use a separate variable or a separate try-with-resources
Using the resource in catch or finally Compile error cannot find symbol: the variable is out of scope Store the data you need in a variable declared before try
Wrapper in one declaration: new ObjectInputStream(new FileInputStream(f)) The ObjectInputStream constructor reads the stream header and may throw StreamCorruptedException; the inner FileInputStream was never declared as a resource and stays open Declare each stream as its own resource: try (FileInputStream in = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(in))
Files.lines(path) or Files.list(dir) without try-with-resources The Stream keeps a file handle open until garbage collection; under heavy load you get “Too many open files” try (Stream<String> lines = Files.lines(path)) { ... }
Declaring new Scanner(System.in) as a resource System.in gets closed; the next console read throws NoSuchElementException Do not close standard input; see User input with Scanner
Assuming try-with-resources catches exceptions It only closes resources; a checked IOException without catch or throws does not compile Add a catch block or declare the exception in throws

Frequently Asked Questions

Does Kotlin have try-with-resources?

Kotlin has no separate statement for it — the use { } extension function for Closeable and AutoCloseable plays that role: BufferedReader(FileReader(path)).use { it.readLine() }. It calls close() after the lambda finishes, including when an exception is thrown, and adds an exception from close() to the main one as suppressed. For several resources, nest the use calls.

What happens if a resource is null?

Nothing bad: try (BufferedReader br = null) { } compiles and runs without a NullPointerException. According to the language specification, close() is simply not called for a resource whose value is null. An NPE happens only if you use such a resource inside the try block.

Do I need to call flush() before a writer is closed in try-with-resources?

No. close() on BufferedWriter, PrintWriter and BufferedOutputStream flushes the buffer first and then closes the stream. flush() is needed only when the data must reach the file before closing — for example, when the same file is read by another stream inside the same try block.

Which runs first: close(), catch or finally?

All resources are closed first (in reverse declaration order), then catch runs, and finally runs last. This is a frequent interview question; an example with output is in the section catch and finally in try-with-resources.

Can I use try-with-resources with JDBC?

Yes, and it is the recommended way: Connection, Statement, PreparedStatement and ResultSet implement AutoCloseable. They are usually declared in one pair of parentheses — try (Connection c = ds.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) — and closed in reverse order: the statement first, then the connection.

Comments

Please log in or register to have a possibility to add comment.