Ditch Vavr: Native Java 21 Sealed Result Pattern Matching Is All You Need
Stop bloating your Spring Boot microservices with third-party FP libraries like Vavr just to avoid runtime exceptions. Java 21's sealed interfaces and record patterns give you type-safe, zero-dependency railway-oriented error handling built straight into the JDK.
Why Most Developers Get This Wrong
- Importing Vavr or Arrow purely for
EitherorTry, dragging unnecessary transitive dependencies into modern microservices. - Throwing runtime exceptions for predictable domain failures, which destroys performance through stack trace generation and hides errors from method signatures.
- Building custom
Resultwrappers that rely on clunkyinstanceofchecks or deeply nested lambda callbacks instead of native language features.
The Right Way
Model domain outcomes as a generic sealed hierarchy and consume them using exhaustive record pattern matching in switch expressions.
- Define a generic
sealed interface Result<T, E>restricted strictly toSuccess<T>andFailure<E>records. - Return
Resultexplicitly from service methods to force caller handling at compile time. - Deconstruct record payloads directly inside switch expressions without explicit casts or getter clutter.
- Eliminate fallback
defaultcases so the compiler catches unhandled error states instantly during refactoring.
Show Me The Code
public sealed interface Result<T, E> {
record Success<T, E>(T value) implements Result<T, E> {}
record Failure<T, E>(E error) implements Result<T, E> {}
}
// Consuming domain results via record deconstruction
public String processPayment(Result<Transaction, PaymentError> result) {
return switch (result) {
case Result.Success(var tx) -> "Paid: " + tx.id();
case Result.Failure(PaymentError.InsufficientFunds e) -> "Low balance: " + e.amount();
case Result.Failure(PaymentError.GatewayTimeout e) -> "Retry later";
};
}
Key Takeaways
- Zero-Dependency FP: Ditch legacy functional libraries; JDK 21 provides all the language primitives you need for robust error handling.
- Compiler-Enforced Safety: Exhaustive switch expressions eliminate unhandled edge cases at compile time without runtime guard clauses.
- Explicit Domain Flow: Deconstructing records in switch arms produces clean, readable code that treats errors as first-class domain concepts rather than unexpected disruptions.
Shameless plug: javalld.com has full LLD implementations with step-by-step execution traces — free to use while prepping.
Top comments (0)