Sealed Classes

Restricting Inheritance (Java 17)

A sealed class or interface lists exactly which classes may extend it with permits. Each permitted subclass must be final, sealed or non-sealed. This models "one of a fixed set" (like enums, but each case can carry different data).

Example

Because the compiler knows every subtype, a switch over a sealed type needs no default.

public class Main {
    static String describe(Payment p) {
        return switch (p) {
            case Upi u -> "UPI to " + u.vpa();
            case Card c -> "Card ending " + c.last4();
            case NetBanking n -> "NetBanking via " + n.bank();
        };                                  // exhaustive: no default needed
    }

    public static void main(String[] args) {
        Payment[] payments = { new Upi("ravi@okhdfc"), new Card("4242"), new NetBanking("SBI") };
        for (Payment p : payments) System.out.println(describe(p));
    }
}

sealed interface Payment permits Upi, Card, NetBanking {}
record Upi(String vpa) implements Payment {}
record Card(String last4) implements Payment {}
record NetBanking(String bank) implements Payment {}

Output

UPI to ravi@okhdfc
Card ending 4242
NetBanking via SBI

Why It Helps

  • Adding a new subtype (say Wallet) makes every non-exhaustive switch a compile error — the compiler finds all places to update.
  • Great for domain results: sealed interface Result permits Success, Failure, API responses, UI states, commands/events.
  • Records + sealed interfaces = algebraic data types in Java.