Compact canonical constructor — validation without parameter list repetition.
Regular constructor:
1public record Person(String name, int age) {2 public Person(String name, int age) {3 this.name = name;4 this.age = age;5 }6}
Compact canonical constructor:
1public record Person(String name, int age) {2 public Person {3 // Validation only4 if (name == null || name.isBlank()) {5 throw new IllegalArgumentException("Name cannot be blank");6 }7 if (age < 0 || age > 150) {8 throw new IllegalArgumentException("Invalid age");9 }10 // Fields assigned automatically after this block11 }12}
How it works step-by-step:
this.name = name in a compact constructor — the compiler does it.Real-world example with normalization:
1public record Email(String address) {2 public Email {3 if (address == null || !address.contains("@")) {4 throw new IllegalArgumentException("Invalid email: " + address);5 }6 // Note: we cannot do address = address.toLowerCase() here7 // because compact constructors assign fields after the body8 }9}1011// For normalization, use a regular canonical constructor12public record Email(String address) {13 public Email(String address) {14 this.address = address != null ? address.toLowerCase() : null;15 }16}
Benefits: