W3docs

Java try-with-resources

Automatically close AutoCloseable resources in Java with the try-with- resources statement.

Java try-with-resources

The try-with-resources statement is Java's solution to the "open it, use it, always close it" pattern. You declare a resource at the top of the try, and the JVM guarantees it will be closed when the block exits — whether the block returned normally, threw an exception, or was abandoned by some other control flow. The verbose finally dance the previous chapter ended on collapses into a single declaration.

The shape

try (FileReader reader = new FileReader(path)) {
  // use reader
}

That's it. No finally, no explicit close(). When the try exits, the JVM calls reader.close() automatically. Any catch and finally clauses you add still work — they run after the resource is closed.

try (FileReader reader = new FileReader(path)) {
  // use reader
} catch (IOException e) {
  // handle — at this point the reader is already closed
}

What can be a resource

A resource has to implement AutoCloseable (or its older subinterface Closeable). That interface declares a single method:

public interface AutoCloseable {
  void close() throws Exception;
}

Most types you'd reach for already implement it: InputStream, OutputStream, Reader, Writer, Connection, Statement, ResultSet, Scanner, Lock wrappers, and many third-party clients. If you're writing a class that owns a resource, you implement AutoCloseable yourself.

Multiple resources

Separate declarations with semicolons. Resources are closed in reverse order of declaration, so the last opened is the first closed:

try (
  FileInputStream  in  = new FileInputStream(src);
  FileOutputStream out = new FileOutputStream(dst)
) {
  in.transferTo(out);
}
// closes `out` first, then `in`

Reverse order matters because the second resource often depends on the first. Closing the dependent one first leaves the foundation intact for one more moment, which is the safer order.

Reusing existing resources (Java 9+)

If you already have a variable holding an AutoCloseable, you don't have to declare a new one — pass it by name:

BufferedReader reader = openSomewhere();
try (reader) {
  // use it
}

The variable must be final or effectively final (you can't reassign it). This form is useful when a resource is constructed elsewhere — at the cost of making the close less visible. Use it when the existing variable is right there; otherwise prefer the inline declaration.

Suppressed exceptions

Here's the subtle part. What happens if the try body throws and the close() call also throws? Pre-Java 7, the finally's close-exception would replace the original — and you'd lose the real cause.

try-with-resources solves this. The original exception is the one thrown to the caller; any close-time exceptions are attached to it as suppressed exceptions, retrievable with Throwable.getSuppressed():

try (Resource r = new Resource()) {
  r.use();          // throws A
}                   // close() throws B
// caller sees A;
// A.getSuppressed() returns [B]

The default printStackTrace() prints suppressed exceptions too (Suppressed: ... lines under the main one). You almost never have to handle this manually — the language preserves the chain for you.

A typical real shape

A common pattern, putting everything together:

public List<String> readAllLines(Path p) throws IOException {
  try (BufferedReader reader = Files.newBufferedReader(p)) {
    return reader.lines().toList();
  }
}

Things to notice: no explicit close, no finally, the body can return directly, and the caller still gets a clean IOException if anything failed.

When try-with-resources is the wrong tool

It's the right tool whenever you own the whole lifetime of the resource for one block. It's wrong when:

  • The resource lives longer than the block — for instance, a connection cached across calls. Closing it at the end of the method would break the next user.
  • You don't own the resource — a caller handed it to you. They'll close it themselves.

In those cases, leave the close to the owner. If you can't tell who the owner is, that's a design smell — figure it out before writing the code.

A worked example

A short program that copies a string to an in-memory pipe and reads it back through a buffered reader. Both streams are AutoCloseable; both get closed automatically; we add a tiny custom resource so you can see the close order in the output.

java— editable, runs on the server

In the output you can see the declaration order is a, b, src, buf but the close order is reverse: buf, src, b, a. That's the language guarantee — first opened, last closed.

What's next

Up to now we've only been catching exceptions Java threw at us. Real code also needs to raise its own — for invalid arguments, broken invariants, or domain failures. Continue to Java throw and throws.

Practice

Practice

A `try-with-resources` block opens two `AutoCloseable` resources. The body throws an `IOException`, and the `close()` of the second resource also throws an `IOException`. What does the caller see?