7. Records & Sealed Classes

Modern Java - Record Classes & Sealed Class Hierarchies

Deep dive into Java 14+ Records (immutable data carriers, compact constructors) and Java 17 Sealed Classes (permits clause, non-sealed, switch exhaustiveness).

📇 Modern Record Classes (Java 14+)

A Record is a specialized, immutable data-carrier class introduced in Java 14. When declaring a record, the javac compiler automatically generates final fields, a canonical constructor, component getters, equals(), hashCode(), and toString() implementations:

  • Analogy: An Immutable Laminated Passport Card.
    • Traditional Java POJO: Carrying a loose paper notebook where anyone can tear out pages, overwrite names (setFirstName()), or erase dates. Requires 100 lines of boilerplate boilerplate code (getters, setters, equals, hashCode).
    • Java record: A tamper-proof laminated Passport Card stamped at the government office (record UserDto(...)). Immutable fields, zero boilerplate, and verified structural integrity!
// Traditional POJO (Requires 60+ lines of code) vs Modern Java Record (1 Line!)
public record UserDto(Long id, String username, String email) {
    
    // Optional: Compact Constructor for Validation Invariants
    public UserDto {
        if (id <= 0) {
            throw new IllegalArgumentException("User ID must be positive.");
        }
        if (email == null || !email.contains("@")) {
            throw new IllegalArgumentException("Invalid user email address.");
        }
    }
}
public class RecordDemo {
    public static void main(String[] args) {
        UserDto user1 = new UserDto(101L, "alice_dev", "[email protected]");
        
        // Auto-generated Component Accessors (No 'get' prefix!)
        System.out.println("Username: " + user1.username());
        System.out.println("User String: " + user1); // Auto toString()!
        
        UserDto user2 = new UserDto(101L, "alice_dev", "[email protected]");
        System.out.println("Structural Equals: " + user1.equals(user2)); // TRUE!
    }
}

🔒 Sealed Classes & Restricted Hierarchies (Java 17+)

Sealed Classes (sealed) restrict which specific child classes or interfaces are permitted to inherit from them using the permits clause:

  • Analogy: Gated Security Access Clearance. Instead of allowing any unknown class in the building to extend Shape (public class RogueShape extends Shape), a Sealed Class acts like a VIP guest list: "Only Circle, Rectangle, and Square are permitted through this entrance!"
                              Sealed Class Hierarchy

                        sealed class Shape permits Circle, Rectangle

        ┌────────────────────────────────┴────────────────────────────────┐
        ▼                                                                 ▼
final class Circle extends Shape                         non-sealed class Rectangle extends Shape
(Sub-hierarchy closed completely)                        (Sub-hierarchy unlocked for open extension)
// 1. Sealed Base Interface
public sealed interface Shape permits Circle, Rectangle, Triangle {}

// 2. Permitted Subclass 1: Sealed child MUST be marked 'final', 'sealed', or 'non-sealed'
public final class Circle implements Shape {
    private final double radius;
    public Circle(double radius) { this.radius = radius; }
    public double radius() { return radius; }
}

// 3. Permitted Subclass 2
public final class Rectangle implements Shape {
    private final double width, height;
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    public double width() { return width; }
    public double height() { return height; }
}

// 4. Permitted Subclass 3
public final class Triangle implements Shape {}

🔀 Sealed Classes with Switch Pattern Matching (Java 21)

Combining Sealed Classes with Java 21 Switch Pattern Matching guarantees Exhaustiveness Checking at compile-time, eliminating the need for redundant default branches:

public class SealedSwitchDemo {
    public static double calculateArea(Shape shape) {
        // Exhaustiveness Checked by javac! No default branch needed!
        return switch (shape) {
            case Circle c -> Math.PI * c.radius() * c.radius();
            case Rectangle r -> r.width() * r.height();
            case Triangle t -> 0.5 * 10 * 5; // Simplified calculation
        };
    }

    public static void main(String[] args) {
        Shape shape = new Circle(5.0);
        System.out.println("Calculated Area: " + calculateArea(shape));
    }
}

❓ Conceptual Quizzes

Knowledge Check

What are the automatic features generated by javac when defining a Record class in Java 14+?

Knowledge Check

Which three modifiers are valid choices for a subclass that extends a sealed parent class?


💻 Practice Problems

Problem: Immutable Financial Order Record

Create an immutable OrderRecord record containing orderId (Long), customerName (String), and amount (double). Include a compact constructor that validates amount > 0.

On this page