Sealed Classes & Pattern Matching
Sealed classes (Java 17, stable) restrict which classes can extend or implement them, declared with the permits clause. Combined with pattern matching in switch (Java 21, stable), they enable exhaustive type switching.
Sealed class = a VIP guest list at a party. Only the names on the 'permits' list can get in. The compiler is the bouncer who checks every switch-case against the guest list -- no default needed if everyone's accounted for.
Permitted subclasses must be in the same compilation unit (or same package with --enable-preview in some versions) and must be final, sealed, or non-sealed. Sealed classes enable the compiler to verify exhaustiveness in switch expressions — if all permitted subtypes are handled, no default branch is needed. Records are implicitly final and work naturally as sealed class leaves. This models algebraic data types (sum types) from functional languages.
Sealed types with pattern matching in switch (JEP 441, Java 21) allow: case Shape s when s.area() > 100 — combining type checks with guard clauses. This replaces the visitor pattern in many codecs and AST transformation scenarios without the verbosity. Sealed hierarchies are also leveraged by the compiler for null analysis and by serialization frameworks (Jackson supports sealed classes via PolymorphicTypeValidator). The combination of sealed classes + records + pattern matching + switch expressions brings Java ADT expressiveness close to Kotlin's sealed class + when.
Sealed classes let you declare all permitted subtypes at compile time, enabling the compiler to enforce exhaustive pattern matching. This is the Java way to express algebraic sum types — useful for modeling things like Result<T> (Ok | Err), event hierarchies, or AST nodes where you own all variants. In Java 21+, switch expressions over sealed types with pattern matching eliminate boilerplate instanceof chains and make illegal states unrepresentable.
Sealed classes only restrict direct subclassing — a non-sealed permitted subclass can itself be freely extended, breaking the exhaustiveness guarantee.