try-with-resources, AutoCloseable, and suppressed exceptions
Resources declared in the try(...) parens get close() called automatically, in reverse declaration
order, even if the body throws. If close() itself throws while an exception from the body is already
propagating, the close-time exception isn't lost -- it's attached to the primary one as a suppressed
exception, retrievable via getSuppressed(), rather than silently replacing the original.
class NoisyResource implements AutoCloseable {
String name;
NoisyResource(String name) { this.name = name; System.out.println(" open " + name); }
public void close() { System.out.println(" close " + name); }
}
try (var a = new NoisyResource("A"); var b = new NoisyResource("B")) {
System.out.println(" using both");
}
// note the close order below: B, then A -- reverse of declaration order
class FailingResource implements AutoCloseable {
public void close() throws Exception {
System.out.println(" close FailingResource (throws)");
throw new IllegalStateException("close failed");
}
}
try {
try (var f = new FailingResource()) {
throw new RuntimeException("primary failure in body");
}
} catch (RuntimeException e) {
System.out.println("primary exception: " + e.getMessage());
for (Throwable suppressed : e.getSuppressed()) {
System.out.println("suppressed: " + suppressed.getClass().getSimpleName() + ": " + suppressed.getMessage());
}
}