Abstraction and Modern Types · Lesson 28 of 42
Records, Enums and Sealed Classes
Modern Java added types that remove boilerplate and make intent obvious. Records are one-line immutable data classes, enums model a fixed set of values, and sealed classes let you list exactly which subclasses may exist. Together with pattern matching, they make Java 21 code shorter and safer – and they are now common in Spring Boot projects.
In this lesson
- Records: data classes in one line
- Enums with fields, methods and switch
- Sealed interfaces and classes
- Putting them together with pattern matching
Records
A record declares its data once; Java generates the constructor, accessors, equals(), hashCode() and toString(). All fields are final.
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Product p = new Product("Headphones", 1499.0, 2);
System.out.println(p);
System.out.println(p.name() + " total ₹" + p.total()); // accessor: name(), not getName()
System.out.println(p.equals(new Product("Headphones", 1499.0, 2)));
Set<Product> set = new HashSet<>(Set.of(p));
System.out.println(set.contains(new Product("Headphones", 1499.0, 2)));
try {
new Product("Pen", -5, 1);
} catch (IllegalArgumentException e) {
System.out.println("Rejected: " + e.getMessage());
}
}
}
record Product(String name, double price, int qty) {
Product { // compact constructor: validation
if (price < 0) throw new IllegalArgumentException("negative price");
}
double total() { return price * qty; } // records can have methods
}
Product[name=Headphones, price=1499.0, qty=2] Headphones total ₹2998.0 true true Rejected: negative price
When to use a record
For data carriers: API request/response objects (DTOs), map keys, results that return several values, events. A record can't extend another class and its fields can't be changed, so it isn't suitable for entities that change over time, such as a JPA @Entity.
Enums
An enum is a type with a fixed set of named constants. It's far safer than using strings or ints for statuses – the compiler rejects typos.
public class Main {
public static void main(String[] args) {
OrderStatus s = OrderStatus.SHIPPED;
System.out.println(s + " " + s.ordinal() + " " + s.label());
System.out.println(OrderStatus.valueOf("DELIVERED").isFinal());
for (OrderStatus st : OrderStatus.values()) System.out.print(st.name() + " ");
System.out.println();
String msg = switch (s) {
case PLACED -> "We have your order";
case SHIPPED -> "On the way";
case DELIVERED -> "Enjoy!";
case CANCELLED -> "Refund started";
};
System.out.println(msg);
}
}
enum OrderStatus {
PLACED("Order placed"), SHIPPED("Shipped"), DELIVERED("Delivered"), CANCELLED("Cancelled");
private final String label; // enums can have fields…
OrderStatus(String label) { this.label = label; } // …constructors (always private)
String label() { return label; } // …and methods
boolean isFinal() { return this == DELIVERED || this == CANCELLED; }
}
SHIPPED 1 Shipped true PLACED SHIPPED DELIVERED CANCELLED On the way
- Enum constants are singletons, so comparing with
==is correct and fast. - A switch expression over an enum needs no
defaultif every constant is handled – and the compiler will warn you if a new constant is added later and not handled. EnumMapandEnumSetare efficient collections keyed by enums.
Sealed classes and interfaces
A sealed type lists the only classes allowed to extend or implement it. That tells readers – and the compiler – the complete set of possibilities.
public class Main {
static double area(Shape s) {
return switch (s) { // no default needed: the compiler knows all cases
case Circle c -> Math.PI * c.r() * c.r();
case Rect(double w, double h) -> w * h; // record pattern: unpack fields
case Square sq -> sq.side() * sq.side();
};
}
public static void main(String[] args) {
Shape[] shapes = {new Circle(1), new Rect(4, 3), new Square(2)};
for (Shape s : shapes) System.out.printf("%s → %.2f%n", s, area(s));
}
}
sealed interface Shape permits Circle, Rect, Square {}
record Circle(double r) implements Shape {}
record Rect(double w, double h) implements Shape {}
record Square(double side) implements Shape {}
Circle[r=1.0] → 3.14 Rect[w=4.0, h=3.0] → 12.00 Square[side=2.0] → 4.00
sealed interface Shape
Shape permits exactly…
- Circlerecord (implicitly final)
- Rectrecord
- Squarerecord
Permitted subclasses must be final, sealed or non-sealed. Records are implicitly final, which makes "sealed interface + records" a neat way to model results, events and API responses.
Practice
Try it yourself
Create an enum
Planet-styleCoinwith values PAISE_50(0.5), RUPEE_1(1), RUPEE_2(2) and sum one of each.Show solution
public class Main { public static void main(String[] args) { double total = 0; for (Coin c : Coin.values()) total += c.value; System.out.println(total); } } enum Coin { PAISE_50(0.5), RUPEE_1(1), RUPEE_2(2); final double value; Coin(double value) { this.value = value; } }3.5
Write a record
Range(int from, int to)that rejects from > to and has alength()method.Show solution
public class Main { public static void main(String[] args) { Range r = new Range(3, 10); System.out.println(r + " length " + r.length()); } } record Range(int from, int to) { Range { if (from > to) throw new IllegalArgumentException("from > to"); } int length() { return to - from; } }Range[from=3, to=10] length 7
Quick check
What does a record generate automatically?
A canonical constructor, accessor methods, equals(), hashCode() and toString().
Can you compare enum values with ==?
Yes – each constant is a single instance.
Why does a switch over a sealed interface need no default?
The compiler knows every permitted subtype, so it can check that all cases are covered.
Summary
- Records: immutable data classes with generated equals/hashCode/toString; validate in a compact constructor.
- Enums: fixed sets of values with fields, methods and exhaustive switches.
- Sealed types list their subclasses; with record patterns, switches become complete and concise.
Interview practice: Java 8 to 21 features.
Finished this lesson?
Mark it complete to track your progress, then carry on with the next lesson.