Java 10: Sealed Classes (Java 17)
easy⏱ 5 mincoursejava
sealed permits
sealed class Shape permits Circle, Square, Triangle {} — only the three named subtypes are allowed. Each subtype must be final, sealed, or non-sealed (explicitly opts back into open hierarchy). The compiler now knows the complete set of subtypes, enabling exhaustive checks.
public sealed interface Result<T> permits Success, Failure {}
public record Success<T>(T value) implements Result<T> {}
public record Failure<T>(String reason) implements Result<T> {}
Exhaustive switch expressions
With a sealed type, switch (result) over Result<T> lets the compiler verify every case is covered. Missing a case is a compile error. Add a new Pending variant later and every switch in your codebase fails to compile until you handle it — this is the killer feature. Compare to untagged subclasses where you rely on a default branch and hope.
String describe(Result<User> r) {
return switch (r) {
case Success<User> s -> "got " + s.value().name();
case Failure<User> f -> "failed: " + f.reason();
// no default — compiler ensures exhaustiveness
};
}
sealed vs enum vs union type
Enum: fixed set of instances, each a stateless constant. Sealed: fixed set of subtypes, each with its own state and fields. Union (TypeScript): compile-time tag, no runtime class. Sealed classes are the Java answer to ADTs (algebraic data types) — used heavily in functional patterns like Optional, Result, AST nodes, state machines.
Build a Result<T> with exhaustive match
Define a discriminated-union Result<T> = Success<T> | Failure using TS's tagged-union equivalent. Write describe(r) using a switch (r.kind) that the compiler proves is exhaustive (TS's never trick). Then add a Pending variant and watch every caller's type check fail until updated.
Use sealed for state machines
Any state machine — Draft | Submitted | Approved | Rejected — is a perfect fit. The compiler ensures every transition handler covers every state. Combined with records for payload, you get a fully-checked finite-state-machine in ~10 lines of Java.
Quiz: non-sealed
When do you use non-sealed? When you want the sealed parent to define its direct children, but one of those children should itself be openly extensible. For example, a sealed Shape permits Circle, Polygon where non-sealed class Polygon can be extended freely — the seal stops at Polygon.