DEV Community

Cover image for Try-With-Resources In Java
Adesola
Adesola

Posted on

Try-With-Resources In Java

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();
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

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);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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());
}

Enter fullscreen mode Exit fullscreen mode

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)