Interview Prep Zoneby CuriouserLabs

Question 2 of 5 · senior level

How does try-with-resources work, and what problem do suppressed exceptions solve?

🎤 Say this first

Any AutoCloseable declared in the try header is closed automatically in reverse order of declaration, whether the body completes or throws. If the body throws A and close() then throws B, pre-Java-7 finally code would lose A; try-with-resources instead throws A with B attached via addSuppressed() — the primary failure survives, and the close failure is preserved as evidence. It's strictly safer and shorter than manual finally-close pyramids.

The full picture

Reverse-order close + suppression
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(); } — if rs.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 (Writer flushing being the classic hard case).

🔄 Likely follow-up questions

  • Why reverse-order closing? Give a case where order matters. (statement before connection)
  • When would you implement AutoCloseable on a non-I/O class?
  • How does Cleaner relate to close() as a safety net (Effective Java Item 8)?