try-with-resources
Some things a program opens must be closed: a file, a database connection, a network connection. A file left open keeps system resources busy, and what was written to it may never reach the disk. You can close such things in finally, but that code is long, and people often forget to write it.
Remember the door from the lesson on finally. Now picture a door with a closer, a spring that shuts it by itself. You walk through, and the door closes without your help. Java can open things the same way: in a special try that closes them by itself.
public class Main {
public static void main(String[] args) {
try (Door door = new Door("A")) {
System.out.println("inside " + door.name());
}
System.out.println("after");
}
}
record Door(String name) implements AutoCloseable {
@Override
public void close() {
System.out.println("close " + name);
}
}The program prints:
inside A
close A
afterA resource and AutoCloseable
A resource is an object that has to be closed after use. Let's go through the program step by step:
record Door(String name) implements AutoCloseableis our door resource.AutoCloseableis an interface from the standard library with one method,close(), andDoorimplements it.try (Door door = new Door("A"))declares the resource in parentheses right aftertry.- The body of the block prints
inside A. - On the way out of the block, Java calls
door.close()by itself, andclose Ais printed. - Then the code after
tryruns and printsafter.
try-with-resources is a try with resources in parentheses: when the block is left, it calls close() on each of them. The compiler turns such a try into try and finally with a call to close(), the very code you would otherwise write by hand.
Only an object of a class that implements AutoCloseable can be a resource. In the interface, the method close() is declared with throws Exception. Our Door throws nothing and does not write throws, so no catch is needed here.
Interviewers ask: what is try-with-resources, and what does a resource need? The answer: a block that closes its resources by itself whichever way it is left, and a resource must implement AutoCloseable.
Several resources
Resources in the parentheses are separated by semicolons:
try (Door a = new Door("A"); Door b = new Door("B")) {
System.out.println("inside " + a.name() + b.name());
}inside AB
close B
close AResources close in reverse order: the last one opened closes first. It is the same with doors: you walked in through A, then through B, and on the way out you pass B first. So a resource opened later may use one opened earlier: while it is closing, the earlier one still works.
An exception inside try
A resource is closed whichever way the block is left, an exception included:
try (Door door = new Door("C")) {
System.out.println("inside " + door.name());
Integer.parseInt("x");
} catch (NumberFormatException e) {
System.out.println("caught");
}inside C
close C
caughtThe exception broke off the body of the block, but the door closed anyway. And it closed before the catch ran: Java first closes the resources and then looks for whoever will answer the alarm.
Here the door-closer picture is imprecise. A real door closes as soon as you have walked through. A resource closes only at the end of the whole try block, and inside the block you can work with it.
Common mistake
The door got its close() method, but the interface was forgotten:
record Door(String name) { // ✗
public void close() {
System.out.println("close " + name);
}
}error: incompatible types: try-with-resources not applicable to variable typeA program with try (Door door = new Door("A")) does not compile, although the door has a close() method. The compiler looks not at the method but at the type: only an AutoCloseable may go into the parentheses of try. It reports the error at the try line and adds Door cannot be converted to AutoCloseable, but the fix belongs in the record's header: record Door(String name) implements AutoCloseable.
Key points
- try-with-resources calls
close()on each resource by itself whichever way the block is left. - A resource is an object of a class that implements
AutoCloseable. - Several resources close in reverse order: the last one opened closes first.
- On an exception, the resources close before
catchruns.