javaintermediate
Records and Sealed Types — ADT Modeling
Model algebraic data types with records and sealed interfaces for type-safe domain modeling.
javaPress ⌘/Ctrl + Shift + C to copy
import java.util.List;
// Sealed hierarchy — Result type (like Rust's Result)
public sealed interface Result<T> {
record Ok<T>(T value) implements Result<T> {}
record Err<T>(String message, Exception cause) implements Result<T> {
Err(String message) { this(message, null); }
}
default <U> Result<U> map(java.util.function.Function<T, U> fn) {
return switch (this) {
case Ok<T> ok -> new Ok<>(fn.apply(ok.value()));
case Err<T> err -> new Err<>(err.message(), err.cause());
};
}
default <U> Result<U> flatMap(java.util.function.Function<T, Result<U>> fn) {
return switch (this) {
case Ok<T> ok -> fn.apply(ok.value());
case Err<T> err -> new Err<>(err.message(), err.cause());
};
}
default T orElse(T fallback) {
return switch (this) {
case Ok<T> ok -> ok.value();
case Err<T> err -> fallback;
};
}
static <T> Result<T> of(java.util.concurrent.Callable<T> action) {
try { return new Ok<>(action.call()); }
catch (Exception e) { return new Err<>(e.getMessage(), e); }
}
}
// Domain events as sealed types
sealed interface DomainEvent {
record UserRegistered(String userId, String email, java.time.Instant at) implements DomainEvent {}
record OrderPlaced(String orderId, List<String> items, double total) implements DomainEvent {}
record PaymentReceived(String orderId, String txId, double amount) implements DomainEvent {}
record OrderShipped(String orderId, String trackingNo) implements DomainEvent {}
}
// Expression tree
sealed interface Expr {
record Num(double value) implements Expr {}
record Add(Expr left, Expr right) implements Expr {}
record Mul(Expr left, Expr right) implements Expr {}
record Neg(Expr expr) implements Expr {}
static double eval(Expr expr) {
return switch (expr) {
case Num n -> n.value();
case Add a -> eval(a.left()) + eval(a.right());
case Mul m -> eval(m.left()) * eval(m.right());
case Neg neg -> -eval(neg.expr());
};
}
}
class Demo {
public static void main(String[] args) {
// Result usage
Result<Integer> parsed = Result.of(() -> Integer.parseInt("42"));
Result<String> formatted = parsed.map(n -> "Number: " + n);
System.out.println(formatted); // Ok[value=Number: 42]
Result<Integer> failed = Result.of(() -> Integer.parseInt("abc"));
System.out.println(failed.orElse(0)); // 0
// Expression tree
Expr expr = new Expr.Add(
new Expr.Num(3),
new Expr.Mul(new Expr.Num(4), new Expr.Num(5))
);
System.out.println(Expr.eval(expr)); // 23.0
}
}Use Cases
- Type-safe error handling with Result type
- Domain event modeling in event-driven systems
- Expression trees and interpreter patterns
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
javabeginner
Java Records — Immutable Data Classes
Use Java records for concise immutable data carriers with built-in equals, hashCode, and toString.
Best for: Replacing verbose POJO classes with concise records
#java#records
kotlinintermediate
Sealed Hierarchies for Domain Modeling
Use sealed interfaces and classes for exhaustive domain modeling with when expressions.
Best for: Payment processing with type-safe methods
#kotlin#sealed
javabeginner
Reverse a String in Java
Multiple ways to reverse a string in Java including StringBuilder, char array, and stream approaches.
Best for: String manipulation in coding interviews
#java#string
javabeginner
Read File Line by Line in Java
Read files using BufferedReader, Files.readAllLines, and Stream API with proper resource management.
Best for: Processing log files line by line
#java#file-io