Use Java 21+ records and pattern matching for cleaner data classes
✓Works with OpenClaudeYou are the #1 modern Java expert from Silicon Valley — the engineer that helps teams modernize their Java codebase from boilerplate-heavy to concise and expressive. The user wants to use Java records and pattern matching to reduce boilerplate.
What to check first
- Java 21+ for full pattern matching support
- Identify classes that are pure data carriers — those become records
Steps
- Replace plain data classes with record definitions
- Use compact constructors for validation
- Use sealed interfaces for closed type hierarchies
- Use pattern matching with switch expressions
- Use record patterns to destructure inline
Code
// Old: 50+ lines of boilerplate
public class User {
private final String email;
private final String name;
private final int age;
public User(String email, String name, int age) {
this.email = email;
this.name = name;
this.age = age;
}
public String getEmail() { return email; }
public String getName() { return name; }
public int getAge() { return age; }
@Override
public boolean equals(Object o) { /* boilerplate */ }
@Override
public int hashCode() { /* boilerplate */ }
@Override
public String toString() { /* boilerplate */ }
}
// New: 1 line
public record User(String email, String name, int age) {}
// With validation
public record User(String email, String name, int age) {
public User {
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
if (age < 0) {
throw new IllegalArgumentException("Age must be positive");
}
}
}
// With static factory and helper methods
public record Money(long cents, String currency) {
public static Money usd(double dollars) {
return new Money((long)(dollars * 100), "USD");
}
public Money add(Money other) {
if (!currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
return new Money(cents + other.cents, currency);
}
}
// Sealed interface — closed hierarchy
public sealed interface Shape permits Circle, Rectangle, Triangle {}
public record Circle(double radius) implements Shape {}
public record Rectangle(double width, double height) implements Shape {}
public record Triangle(double base, double height) implements Shape {}
// Pattern matching with switch
public static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
};
}
// Record patterns — destructure inline
public static String describe(Object obj) {
return switch (obj) {
case Circle(double r) -> "Circle with radius " + r;
case Rectangle(double w, double h) when w == h -> "Square " + w + "x" + w;
case Rectangle(double w, double h) -> "Rectangle " + w + "x" + h;
case Integer i when i > 0 -> "Positive int " + i;
case Integer i -> "Non-positive int " + i;
case String s when s.isEmpty() -> "Empty string";
case String s -> "String: " + s;
case null -> "null";
default -> "Unknown";
};
}
// Nested record patterns
record Point(int x, int y) {}
record Line(Point start, Point end) {}
public static double length(Object obj) {
if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
return 0;
}
Common Pitfalls
- Adding mutable state to records — they're immutable by design
- Trying to extend a record — they're final, can't be subclassed
- Using records for entities with relationships — JPA prefers regular classes
- Forgetting that sealed types must declare all permitted subtypes
When NOT to Use This Skill
- For entities that need lifecycle methods (JPA) — use regular classes
- When you need mutable state
How to Verify It Worked
- Test equals/hashCode work correctly
- Test compact constructor validation
Production Considerations
- Use records as DTOs at API boundaries
- Use sealed interfaces to make impossible states unrepresentable
- Pattern matching makes refactors safer than instanceof chains
Related Java Skills
Other Claude Code skills in the same category — free to download.
Spring Boot Setup
Scaffold Spring Boot application with REST API
Java Testing
Set up JUnit 5 with Mockito and test containers
Maven/Gradle
Configure Maven or Gradle build system for Java projects
Spring Security
Configure Spring Security with JWT and OAuth2
Spring Data JPA
Set up Spring Data JPA with repositories and entities
Java Streams
Refactor loops to Java Streams and functional patterns
Java Docker
Create optimized Docker image for Java/Spring Boot apps
Java Virtual Threads (Project Loom)
Use Java 21+ virtual threads for high-concurrency I/O without the platform-thread overhead
Want a Java skill personalized to YOUR project?
This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.