try-with-resources Pattern
`try-with-resources` (Java 7+) automatically closes any object that implements `AutoCloseable` when the block exits, normally or via exception. This snippet covers the basic form, declaring multiple resources, the Java 9 enhancement that lets you reuse an existing variable, and writing your own `AutoCloseable` to participate in the pattern. Use it for every reader, writer, stream, lock, and database connection you open.
1,126 views
26
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class Main {
public static void main(String[] args) throws IOException {
// BufferedReader is AutoCloseable; the try block guarantees close().
try (BufferedReader br = new BufferedReader(new StringReader("hello\nworld"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println("line: " + line);
}
} // close() runs here, even if readLine() threw.
}
}The resource is declared inside the try (...) parentheses; when control leaves the block (normal exit, return, or exception) the runtime calls close() automatically. Compare this with the pre-Java-7 idiom of a try / finally that had to null-check and re-catch close exceptions: a 15-line dance shrinks to four lines. The compiler also wires up suppressed exceptions correctly, so a primary failure inside the block is not lost when close() itself throws.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class Main {
public static void main(String[] args) throws java.io.IOException {
ByteArrayInputStream in = new ByteArrayInputStream("data".getBytes());
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Java 9+ allows naming previously declared resources here.
try (in; out) {
int b;
while ((b = in.read()) != -1) out.write(b);
System.out.println("copied: " + out.toString());
}
// Both close() calls happen here, in REVERSE declaration order.
}
}Multiple resources are separated by semicolons inside the try parentheses. Closure order is the reverse of declaration order, which matters when one resource depends on another (a BufferedWriter wrapping a FileOutputStream, for instance). Java 9 added the ability to list already-declared final (or effectively final) variables instead of re-declaring them, useful when the resource is created elsewhere. Use this when an outer class owns the lifetime but a single block needs deterministic cleanup.
public class Main {
static final class Lease implements AutoCloseable {
final String label;
Lease(String label) {
this.label = label;
System.out.println("acquired " + label);
}
public void use() { System.out.println("using " + label); }
@Override public void close() {
System.out.println("released " + label);
}
}
public static void main(String[] args) {
try (Lease a = new Lease("A");
Lease b = new Lease("B")) {
a.use();
b.use();
throw new RuntimeException("boom");
} catch (RuntimeException e) {
System.out.println("caught: " + e.getMessage());
}
}
}Implement AutoCloseable (or its checked-exception cousin Closeable) and any custom resource type plays nicely with the pattern. The output shows released B before released A: closures fire in reverse declaration order, even when an exception aborts the block. This is the same guarantee you rely on for I/O streams. Reach for a custom AutoCloseable when wrapping a connection pool checkout, a thread-pool task token, or any acquire/release pair where forgetting the release leaks resources.
