Exceptions, Assertions & Logging

Catching, Rethrowing & try-with-resources

Catch what you can handle; wrap-and-rethrow across abstraction boundaries; and let try-with-resources close everything that is AutoCloseable — it is shorter and more correct than any finally block you would write.
  • try-with-resources closes in reverse order, even on exceptions — always prefer it (EJ 9)
  • Suppressed exceptions: a close-failure doesn't mask the real one (getSuppressed)
  • Multi-catch: catch (IOException | SQLException e)
  • Chain causes when translating: throw new StorageException(e) (EJ 73)
  • finally remains for non-resource cleanup (locks, counters)
try-with-resources
try (var in = new Scanner(Path.of("in.txt"), StandardCharsets.UTF_8);
     var out = new PrintWriter("out.txt", StandardCharsets.UTF_8)) {
    while (in.hasNext())
        out.println(in.next().toUpperCase());
}   // out closed first, then in — exception or not

The old finally idiom had two flaws this fixes: nested try/finally noise per resource, and the masking bug — an exception thrown by close() in finally silently discarded the original exception from the body. With try-with-resources the body's exception wins and close-failures attach as suppressed exceptions, visible in the stack trace and via getSuppressed().

Exception translation with cause chaining (EJ Item 73)
public UserProfile loadProfile(String id) {
    try {
        return parse(db.fetchRow(id));
    } catch (SQLException e) {
        // translate low-level detail into the abstraction callers understand,
        // preserving the full diagnostic chain:
        throw new ProfileStoreException("profile " + id, e);
    }
}
Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 7.2 — Catching Exceptions
  • Effective Java (3rd ed.)Items 9, 73, 77