Java › Exceptions

How does exception handling interact with performance, particularly regarding the cost of filling in a stack trace, and how would you optimize exception usage in a performance-critical hot path?

Advanced

Answer

Constructing an exception (specifically, the fillInStackTrace() call invoked by Throwable's constructor, which captures the entire current call stack) has a genuinely measurable performance cost, disproportionately significant if exceptions are being thrown routinely as part of normal, expected control flow in a performance-critical hot path (an anti-pattern in itself -- exceptions should represent exceptional conditions, not routine control flow) -- for cases where you genuinely need lightweight, frequently-thrown exceptions (like in a high-throughput parser signaling routine, expected parse failures), overriding fillInStackTrace() to skip stack trace capture entirely (returning `this` without calling super) can eliminate this overhead, at the obvious cost of losing stack trace information for debugging that specific exception type.
// A lightweight exception for a high-frequency, expected control-flow scenario
public class FastValidationException extends RuntimeException {
    public FastValidationException(String message) {
        super(message, null, false, false);  // disables both suppression AND stack trace capture
    }
}

// vs. the default, which captures a full stack trace on every single construction --
// expensive if thrown thousands of times per second in a hot path
Real-world example A high-throughput data validation pipeline processing millions of records per minute switches its routine, expected-to-occur-frequently ValidationException to disable stack trace capture (using the four-argument Throwable constructor), measurably improving throughput since stack trace capture had become a significant fraction of total processing time at that volume.

Common follow-ups: Why is throwing exceptions for routine, expected control flow generally considered an anti-pattern in the first place, separate from the pure performance cost?;What's lost in debuggability by disabling stack trace capture, and how would you mitigate that trade-off?