Working with Sealed Classes (Java 17+)

1. Creating Sealed Classes

ModifierEffect
sealedRestricts who can extend
permitsLists permitted subclasses
Subclass mustbe final, sealed, or non-sealed
Same modulePermitted types must reside in same module/package

Example: Sealed hierarchy

public sealed class Vehicle permits Car, Truck, Bike { }
public final class Car extends Vehicle { }
public non-sealed class Truck extends Vehicle { }
public sealed class Bike extends Vehicle permits MountainBike { }

2. Using permits Clause

RuleDetail
OptionalIf all permitted types in same file
RequiredIf subclasses are in other files
OrderDoesn't matter

3. Understanding Subclass Modifiers

ModifierMeaning
finalCloses hierarchy at this leaf
sealedContinues with another permits
non-sealedRe-opens for unrestricted extension

4. Using Sealed Interfaces

AspectDetail
ImplementersSame rules: final/sealed/non-sealed
RecordsRecords are implicitly final
Use caseAlgebraic data types (sum types)

5. Understanding Exhaustiveness Checking

ContextBehavior
Switch expression on sealed typeCompiler verifies all permitted types covered
Missing caseCompile error
DefaultOptional (no error if exhaustive)

6. Using Sealed Classes with Pattern Matching

Example: Exhaustive switch

sealed interface Result<T> permits Ok, Err { }
record Ok<T>(T value) implements Result<T> { }
record Err<T>(String msg) implements Result<T> { }

String render(Result<Integer> r) {
    return switch (r) {
        case Ok<Integer>(Integer v) -> "ok: " + v;
        case Err<Integer>(String m) -> "err: " + m;
    };
}
BenefitDetail
No defaultCompiler-enforced exhaustiveness
Refactor-safeAdding subtype → compile error
Smart castPattern variable typed

7. Understanding Design Benefits

BenefitUse
Closed setsDomain modeling (states, events)
Type safetyVisitor pattern alternative
ReflectionTools can list permitted types
vs enumEach variant can have its own data

8. Combining Sealed Classes and Records

Example: ADT

sealed interface Expr permits Num, Add, Mul { }
record Num(double v) implements Expr { }
record Add(Expr l, Expr r) implements Expr { }
record Mul(Expr l, Expr r) implements Expr { }

double eval(Expr e) {
    return switch (e) {
        case Num(double v) -> v;
        case Add(Expr l, Expr r) -> eval(l) + eval(r);
        case Mul(Expr l, Expr r) -> eval(l) * eval(r);
    };
}
PatternResult
Sealed interface + recordsSum-of-products / ADT
Record patternsDestructure inline

9. Understanding Reflection with Sealed Classes

APIReturns
cls.isSealed()boolean
cls.getPermittedSubclasses()Class<?>[]

10. Using Sealed Classes for Domain Modeling

DomainPattern
Order statesealed interface OrderState permits Pending, Paid, Shipped, Cancelled
Payment methodCard / Bank / Crypto record types
ResultOk / Err sum type
AST nodesLit / BinaryOp / UnaryOp