Working with Exception Handling Advanced Patterns

1. Creating Custom Exception Hierarchies

TypeUse
CheckedRecoverable, caller must handle
Unchecked (RuntimeException)Programming errors, optional handling
ErrorJVM-level; do not catch
HierarchyDomain root → specific subclasses

Example: Domain hierarchy

public abstract class DomainException extends RuntimeException {
    protected DomainException(String msg, Throwable cause) { super(msg, cause); }
}
public class NotFoundException extends DomainException {
    public NotFoundException(String id) { super("not found: " + id, null); }
}

2. Using Multi-Catch Blocks (Java 7+)

FormDetail
catch (A | B e)Single handler
e iseffectively final, common-supertype
RestrictionNo subtype + supertype together

3. Using Try-with-Resources (AutoCloseable)

AspectDetail
ResourceImplements AutoCloseable
MultipleSeparated by ;
Close orderReverse declaration
Effectively finalJava 9+: pre-declared resource var allowed
SuppressedExceptions in close added as suppressed

4. Handling Suppressed Exceptions (getSuppressed)

APIUse
e.getSuppressed()Throwable[]
e.addSuppressed(t)Manual add
DisabledConstructor with enableSuppression=false

5. Understanding Exception Translation

PatternUse
Wrap low-levelthrow new ServiceException("...", sql)
Preserve causeAlways pass original
Layer boundaryTranslate at API layer (DAO → service)

6. Using Sneaky Throws Pattern

Example: Sneaky throw

@SuppressWarnings("unchecked")
static <E extends Throwable> void sneakyThrow(Throwable t) throws E { throw (E) t; }
// Usage: sneakyThrow(new IOException("oops"));
ProsCons
No checked declarationHides exception flow
Lambda-friendlySurprising for callers

7. Wrapping Checked Exceptions in Lambdas

Example: Wrapper

public static <T, R> Function<T, R> rethrow(ThrowingFunction<T, R, ?> fn) {
    return t -> { try { return fn.apply(t); }
                   catch (Exception e) { sneakyThrow(e); return null; } };
}
ApproachTrade-off
Throwing FIType-safe
Wrapper utilityLess ceremony
SneakyHides checked

8. Creating Exception Handling Utilities

UtilityUse
Try.of(supplier)Vavr-style result
Retry with backoffResilience4j
Circuit breakerResilience4j / Failsafe
Custom uncheckLambda wrapping

9. Using Result/Either Types for Functional Error Handling

Example: Sealed Result

public sealed interface Result<T, E> {
    record Ok<T, E>(T value) implements Result<T, E> { }
    record Err<T, E>(E error) implements Result<T, E> { }
}
BenefitDetail
Explicit failureType signature documents
Composablemap / flatMap
No exceptionsFor expected errors

10. Understanding Stack Trace Manipulation

APIUse
setStackTrace(StackTraceElement[])Override trace
fillInStackTrace()Re-capture
DisableConstructor flag writableStackTrace=false
StackWalkerModern stack inspection (Java 9+)

11. Understanding Exception Performance Implications

CostMitigation
Stack captureDisable for control-flow exceptions
Throw in hot pathUse Result type instead
Catch overheadNegligible if not thrown
JITOptimizes uncatch'd happy paths

12. Using Chained Exceptions (initCause)

APIUse
new X(msg, cause)Preferred constructor
initCause(t)For exceptions w/o cause ctor
getCause()Walk chain