Try-With-Resources in Java, Explained
If you've worked with files, streams, or database connections in Java, you've probably written something like this at some point:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class StoreApplication {
public static void main(String[] args) throws IOException {
int num = 0;
BufferedReader br = null;
try {
System.out.println("Enter a Number: ");
br = new BufferedReader(new InputStreamReader(System.in));
num = Integer.parseInt(br.readLine());
System.out.println("Number entered is " + num);
} finally {
if (br != null) {
br.close();
}
}
}
}
This works, but notice the ceremony required just to close a reader safely:
- Declare the variable outside the try so it's visible in finally
- Null-check it before closing (because the try might fail before br is ever assigned),
- Remember to do this every single time you open a resource. Forget the null check, or forget close() altogether, and you've got a resource leak.
Java 7 introduced a cleaner way to handle exactly this pattern.
Try-with-resources
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class StoreApplication {
public static void main(String[] args) throws IOException {
int num = 0;
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
System.out.println("Enter a Number: ");
num = Integer.parseInt(br.readLine());
System.out.println("Number entered is " + num);
}
}
}
The resource is declared directly in the parentheses after try, and Java closes it automatically once the block finishes — whether it finishes normally or because an exception was thrown. No finally, no null check, no manual close() call.
Why this works: AutoCloseable
Try-with-resources isn't magic — it only works with types that implement the AutoCloseable interface (or its more specific subtype, Closeable, used by most I/O classes).
AutoCloseable defines a single method, close(), and the compiler generates the equivalent of the old try/finally pattern for you behind the scenes.
This also means you can make your own classes work with try-with-resources by implementing AutoCloseable yourself:
class Connection implements AutoCloseable {
public void query(String sql) {
System.out.println("Running: " + sql);
}
@Override
public void close() {
System.out.println("Connection closed.");
}
}
public class StoreApplication {
public static void main(String[] args) {
try (Connection conn = new Connection()) {
conn.query("SELECT * FROM users");
}
// "Connection closed." is printed automatically here
}
}
Multiple resources
You can open more than one resource in the same try-with-resources statement, separated by semicolons:
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Connection conn = new Connection()
) {
// use both resources
}
Java closes them in reverse order of declaration — so in the example above, conn closes before reader. This matters when resources depend on each other (e.g., a statement that depends on a connection should close before the connection does).
The suppressed-exception problem it quietly fixes
Here's a subtle bug the manual finally pattern has: if the code inside try throws an exception, and close() in finally also throws, the exception from close() overwrites the original one — the real cause of the failure gets silently lost.
Try-with-resources handles this correctly: if both the resource body and close() throw, the body's exception is treated as the primary one, and the exception from close() is attached to it as a suppressed exception, retrievable via getSuppressed(). You don't lose either piece of information.
Java 9+: using an already-declared resource
If a resource variable is already declared and effectively final (never reassigned), you don't have to redeclare it inside the parentheses — you can just reference it:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try (br) {
System.out.println("Number entered is " + br.readLine());
}
This is purely a convenience for cases where the resource is created earlier in the method.
Wrapping up
Try-with-resources is one of those features that looks like minor syntax sugar but actually removes a whole category of bugs: forgotten close() calls, missed null checks, and swallowed exceptions. If you're opening anything that needs closing — files, streams, sockets, database connections — reaching for try-with-resources by default is the safer habit.
Do you have a resource-leak war story from before you knew about this? Share it in the comments.
Top comments (0)