Exceptions and resource safety
Exceptions separate normal return values from exceptional control flow.
Checked and unchecked
Checked exceptions must be caught or declared. Runtime exceptions do not. Use checked exceptions when a caller can reasonably recover and the API should force a decision. Use unchecked exceptions for programming errors, violated preconditions, and failures that most layers cannot meaningfully repair.
Catching
Catch the narrowest useful type. Preserve the original cause when
translating:
throw new ImportException("Cannot import " + file, cause).
Do not catch Exception merely to log and continue with
corrupt state.
Multi-catch handles unrelated alternatives with one block. Catch
order goes from specific to general. A finally block runs
for normal and exceptional completion but should not replace or suppress
the original exception.
Try-with-resources
Resources implementing AutoCloseable close in reverse
declaration order. If both the body and close fail, the body exception
is primary and close failures are suppressed. Inspect
getSuppressed() during diagnosis.
try (var reader = Files.newBufferedReader(path)) {
return reader.lines().toList();
}Domain failures
Do not use exceptions for expected high-volume branching such as “not
found” when a clear result type is better. Sealed results or
Optional can model expected absence; exceptions remain
appropriate for exceptional failure.
Feynman check
An exception is an emergency route. Try-with-resources is a caretaker who locks every opened door even when an emergency happens, and records secondary lock problems without hiding the original emergency.