Java try-with-resources
Table of Contents + β
In the last lesson you learned about the Java finally block. But closing resources by hand in finally is still painful, with extra lines and null checks you can forget. Java gives us a cleaner tool that does the closing for you: try-with-resources.
π€ Why do we need try-with-resources?
Say you open a file and read from it. You must close that file when you are done. With a plain finally, closing one file takes a lot of careful code:
- You declare
readeroutside thetry, just sofinallycan reach it. - You add a null check, because if the file failed to open,
readeris stillnullandclose()would crash. - The
close()call itself can throw, which tangles things further.
What we actually want is to say βopen this, use it, and close it for me when I am done.β That is exactly what try-with-resources does.
π§© What is try-with-resources?
Try-with-resources is a form of try where you declare the resource inside round brackets, like try (Resource r = ...). Java then automatically closes that resource the moment the block ends, whether it finished normally or threw an error.
This is the basic shape:
try (Resource r = openSomething()) { // use r here} // β
Java calls r.close() automatically right hereHere is what makes it special:
- You declare the resource right inside
try(...), not above the try. - Java closes it for you when the block ends, so there is no manual close line.
- It closes even when an exception is thrown inside the block.
- You do not need a
finallyjust for closing, and you do not need null checks.
π Before and after: reading a file
Letβs put the old way and the new way side by side, doing the same job. Both read the first line of a file.
This is the old way with a manual finally close. It works, but notice all the supporting code around the actual work.
import java.io.BufferedReader;import java.io.FileReader;
public class Main { public static void main(String[] args) throws Exception { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("data.txt")); String line = reader.readLine(); System.out.println("First line: " + line); } finally { if (reader != null) { reader.close(); // β manual close with a null check } } }}Now the same thing with try-with-resources. The reader is declared in the brackets, so Java owns the closing.
import java.io.BufferedReader;import java.io.FileReader;
public class Main { public static void main(String[] args) throws Exception { // β
reader is opened in try(...) and closed for us automatically try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) { String line = reader.readLine(); System.out.println("First line: " + line); } // reader.close() happens here on its own, no finally needed }}Output
First line: Hello from the fileCompare the two. The new version has no reader = null, no null check, and no finally. Same result, far less code, and nothing to forget.
π§ What can go in the brackets?
Not every object can sit in try(...). The resource must know how to close itself:
- It has to implement AutoCloseable, an interface with one method called
close(). - A related one,
Closeable, is the same idea aimed at input and output streams. You do not need to memorize the difference. - The everyday resources already support it: files, readers, writers,
Scanner, database connections, network sockets. - So they all drop straight into a try-with-resources.
Here a Scanner is opened in the brackets and closed for you when the block ends.
import java.util.Scanner;
public class Main { public static void main(String[] args) { // β
Scanner implements AutoCloseable, so it works here try (Scanner scanner = new Scanner(System.in)) { System.out.print("Enter your city: "); String city = scanner.nextLine(); System.out.println("You live in " + city); } // scanner.close() runs automatically }}Output
Enter your city: BerlinYou live in BerlinThe Scanner is opened, used, and closed without a single manual close line.
π Opening more than one resource
You often need two things open at once, like reading from one file and writing to another. You can declare several resources in the same try(...). Just separate them with a semicolon.
This opens a reader and a writer together, and both get closed for you.
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;
public class Main { public static void main(String[] args) throws Exception { // β
two resources in one try, both closed automatically try (BufferedReader reader = new BufferedReader(new FileReader("in.txt")); BufferedWriter writer = new BufferedWriter(new FileWriter("out.txt"))) { String line = reader.readLine(); writer.write(line); System.out.println("Copied one line from in.txt to out.txt"); } // both are closed here, no finally needed }}Output
Copied one line from in.txt to out.txtOne nice detail. When you open several resources, Java closes them in the reverse order it opened them. So the writer above closes first, then the reader. The last thing you opened often depends on the first thing, so unwinding backwards is the safe order. And you get it for free.
πͺ Combining with catch
Try-with-resources still works with catch. The closing happens first, then your catch runs. So the order is: use the resource, close it automatically, then handle any error.
This reads a file and catches the case where the file is missing.
import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;
public class Main { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("missing.txt"))) { System.out.println(reader.readLine()); } catch (IOException e) { // β
resource is already closed before we get here System.out.println("Could not read the file: " + e.getMessage()); } }}Output
Could not read the file: missing.txt (No such file or directory)Read the flow. Java opens and uses the reader. The file is missing, so an IOException is thrown. Before jumping to catch, Java closes the reader. Then your catch runs and prints the message. So you get automatic closing and clean error handling in the same compact block.
π Suppressed exceptions, briefly
What if the body throws an error, and then close() also throws while cleaning up? You now have two errors, but only one can travel up as the main one. Here is how Java handles it:
- The error from your body wins. That is the one you really care about.
- The error from
close()is not thrown away. It is attached to the main one as a suppressed exception. - You can still see it later by calling
getSuppressed(). - This beats the old
finallyway, where a failingclose()could hide the real error completely.
You rarely need to act on this, but it is good to know nothing is silently lost.
β οΈ Common Mistakes
A few try-with-resources slip-ups that catch people out. Each shows the wrong way and then the right way.
Still closing the resource by hand in finally. If the resource is in try(...), Java already closes it. Adding a manual close means you close it twice.
// β wrong: double work, Java already closes ittry (Scanner scanner = new Scanner(System.in)) { String name = scanner.nextLine();} finally { scanner.close(); // and this would not even compile, scanner is out of scope}
// β
right: let try-with-resources do the closingtry (Scanner scanner = new Scanner(System.in)) { String name = scanner.nextLine();}Trying to use something that is not AutoCloseable. Only classes that implement AutoCloseable can go in the brackets. A plain object that has no close() method will not compile here.
// β wrong: a normal String is not AutoCloseable, this will not compiletry (String text = "hello") { System.out.println(text);}
// β
right: use a real closeable resourcetry (Scanner scanner = new Scanner("hello")) { System.out.println(scanner.next());}Using the resource after the block ends. Once the block closes, the resource is closed and its name is gone. You cannot touch it afterwards.
// β wrong: scanner is closed and out of scope heretry (Scanner scanner = new Scanner(System.in)) { System.out.println("Inside");}scanner.nextLine(); // does not compile, scanner no longer exists
// β
right: do all your work inside the blocktry (Scanner scanner = new Scanner(System.in)) { String line = scanner.nextLine(); System.out.println(line);}β Best Practices
Habits that make resource handling safe and tidy.
- Prefer try-with-resources for anything closeable. Files, readers, writers, scanners, connections, sockets. If it can be closed, open it in the brackets.
- Do not mix it with a manual close. Once it is in
try(...), Java closes it. Adding your own close is wasted and confusing. - Open each resource in its own slot in the brackets. Separate them with a semicolon and let Java close them in reverse order.
- Keep all the work inside the block. The resource only exists there, so do your reading and writing before the block ends.
- Reach for a plain finally only for non-closeable cleanup. Resetting a flag or printing a final message still belongs in
finally, not here.
π§© What Youβve Learned
Nicely done. Letβs recap try-with-resources in clear points.
- β
try-with-resources declares a resource in
try(...)and closes it automatically when the block ends. - β It closes the resource whether the block finishes normally or throws an error, so nothing is left open.
- β
The resource must implement
AutoCloseable(orCloseable), which most files, scanners, and connections already do. - β
It beats a manual
finallyclose: less code, no forgotten close, no null checks. - β You can open multiple resources in one try, and Java closes them in reverse order.
- β
If both the body and
close()fail, the bodyβs error wins and the close error is kept as a suppressed exception.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does try-with-resources do for you?
Why: A resource declared in try(...) is closed automatically when the block ends, success or failure.
- 2
What must a resource implement to be used in try-with-resources?
Why: The resource must implement AutoCloseable (or Closeable), which provides the close() method Java calls.
- 3
When you open multiple resources, in what order are they closed?
Why: Resources are closed in the reverse order they were opened, which is the safe way to unwind them.
- 4
Why is try-with-resources better than a manual finally close?
Why: It removes the manual close, the null checks, and the extra finally, so there is nothing to forget.
π Whatβs Next?
So far Java has thrown exceptions for us, and try-with-resources has cleaned up after them. But sometimes you want to throw an exception yourself, on purpose, when your code spots a problem like invalid input. The keyword for that is throw. Letβs learn it.