Java Record and Sealed Classes
Java Record Classes
Introduction: Java records, introduced in Java 16, are a type of class that is a transparent holder for shallowly immutable data. Records are meant to simplify the creation of data carrier classes.
Key Features:
-
Conciseness: They reduce boilerplate code by automatically generating getters, equals(), hashCode(), and toString() methods.
-
Immutable Data: Fields in a record are final and immutable by default.
public record Person(String name, int age) {}
In this example, Person is a record with two fields: name and age. The compiler automatically generates a public constructor, public getter methods, equals(), hashCode(), and toString() methods for these fields.
Usage:
Person person = new Person("Alice", 30);
System.out.println(person.name()); // Automatically generated getter
System.out.println(person); // toString() is also automatically generated
Java Sealed Classes
Introduction:
Sealed classes, introduced in Java 17, are used to restrict which other classes or interfaces may extend or implement them. This feature provides more control over inheritance and is useful for defining a closed hierarchy of types.
Key Features:
-
Controlled Inheritance: Only specific classes or interfaces can extend a sealed class.
-
Comprehensive Type Checking: They enable exhaustive type checking at compile time in switch expressions and statements.
Syntax and Example:
First, declare a sealed class with the sealed modifier, listing the permitted subclasses with the permits clause:
public sealed abstract class Shape permits Circle, Square {
abstract double area();
}
Then, define the permitted subclasses using final, sealed, or non-sealed modifiers:
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) { this.radius = radius; }
@Override
double area() { return Math.PI * radius * radius; }
}
public non-sealed class Square extends Shape {
private final double side;
public Square(double side) { this.side = side; }
@Override
double area() { return side * side; }
}
Usage:
Sealed classes are useful in scenarios like creating domain models or working with pattern matching in switch expressions:
Shape shape = getShape(); // Some method returning a Shape instance
double area = switch (shape) {
case Circle c -> c.area();
case Square s -> s.area();
// No need for a default case, as we've covered all possibilities
};
In summary, records simplify the creation and handling of immutable data carrier classes by reducing boilerplate code. Sealed classes allow for the definition of closed hierarchies, providing better control over inheritance and enabling exhaustive type checking in certain scenarios. These features together bring Java closer to a more expressive and less error-prone programming experience.