The full picture
try (var conn = ds.getConnection();
var stmt = conn.prepareStatement(SQL); // closes BEFORE conn
var rs = stmt.executeQuery()) { // closes first
while (rs.next()) process(rs);
} // any close() failure while body threw -> suppressed, not lost
// Reading the evidence later:
catch (SQLException primary) {
for (Throwable t : primary.getSuppressed()) log.warn("also failed", t);
}
// Java 9+: an existing effectively-final resource can be used directly
void handle(Connection conn) throws SQLException {
try (conn) { … } // closes it at the end of the block
}- The old idiom's bug:
finally { rs.close(); stmt.close(); conn.close(); }— ifrs.close()throws, the others never close (leak), and it may mask the body's exception. - Make your own resources
AutoCloseable(pool leases, file locks, metric timers, MDC scopes) — the language then enforces cleanup at every call site. close()should be idempotent and should avoid throwing where possible (Writerflushing being the classic hard case).