JavaintermediateNew
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
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.