Open two resources in one try-with-resources and determine their close order
Resource logs every open and every close. Complete run() so that a resource named A and a resource named B are opened inside a single try-with-resources header, A first, and both are closed automatically when the block ends.
Constraints:
- one
tryheader holding both resources — nofinally, no manualclose()call - then state the exact four lines the program prints, in order
class Resource implements AutoCloseable {
private final String name;
Resource(String name) { this.name = name; System.out.println("open " + name); }
@Override public void close() { System.out.println("close " + name); }
}
void run() {
// your code here
}
Write the implementation.
Declare both resources in one try header, separated by a semicolon. They are closed in reverse order of declaration, so the program prints open A, open B, close B, close A. Reverse order is guaranteed by the language, because a later resource is often built on an earlier one. Every declared resource is closed even if a previous close() threw — that failure is not lost, it is recorded on the propagating exception as a suppressed one.
- ✗Expecting resources to close in declaration order rather than in reverse
- ✗Assuming a failing
close()on one resource leaves the others unclosed - ✗Adding a
finallywith a manualclose()on top of try-with-resources
- →Why does the language close the later resource first instead of the earlier one?
- →Where does a
close()failure go when thetrybody has already thrown?
Solution
void run() {
try (Resource a = new Resource("A");
Resource b = new Resource("B")) {
// work with a and b
}
}
Output:
open A
open B
close B
close A
Why reverse order. The resources in a try header are a sequence of declarations, and a later resource is frequently built on an earlier one (a BufferedWriter over a FileWriter, a PreparedStatement over a Connection). Release has to run from dependent to base, or the later resource would try to finish its work over something already closed. So the language pins the order to reverse — it is a JLS guarantee, not an implementation detail.
Everything gets closed. The compiler expands the header into nested try/finally blocks, so even if B's close() throws, A's close() still runs. The first failure propagates, the second is attached to it as a suppressed exception and is retrievable via getSuppressed() — neither is silently lost.