Week 144 — What is a record pattern and how can one use it?

Question of the Week #144
What is a record pattern and how can one use it?
3 Replies
Eric McIntyre
Eric McIntyre3w ago
Record patterns allow matching an object against a record and extracting the components if the match succeeds. They can be used in both instanceof and switch statements/expressions. For example, take the following record:
record Person(String firstName, String lastName, LocalDate birthday) {}
record Person(String firstName, String lastName, LocalDate birthday) {}
Objects of that class can be matched against that record as follows:
Person max = new Person("Max", "Meier", LocalDate.of(1983, 1, 1));

// check with instanceof
if(max instanceof Person(String firstName, String lastName, LocalDate birthday)) {
System.out.println(firstName + " " + lastName + " is " + Period.between(birthday, LocalDate.now()).getYears() + " years old.");
}

// check with switch
String text = switch(max) {
case Person(String firstName, String lastName, LocalDate birthday) -> firstName + " " + lastName + " is " + Period.between(birthday, LocalDate.now()).getYears() + " years old.";
// other cases possible but not necessary because the compiler knows that max is a Person
};
System.out.println(text);
Person max = new Person("Max", "Meier", LocalDate.of(1983, 1, 1));

// check with instanceof
if(max instanceof Person(String firstName, String lastName, LocalDate birthday)) {
System.out.println(firstName + " " + lastName + " is " + Period.between(birthday, LocalDate.now()).getYears() + " years old.");
}

// check with switch
String text = switch(max) {
case Person(String firstName, String lastName, LocalDate birthday) -> firstName + " " + lastName + " is " + Period.between(birthday, LocalDate.now()).getYears() + " years old.";
// other cases possible but not necessary because the compiler knows that max is a Person
};
System.out.println(text);
Eric McIntyre
Eric McIntyre3w ago
Patterns can also be nested. For example, consider this record containing a component of type Person:
record Employee(Person employee, Employee superior, int monthlySaleryCents) {}
record Employee(Person employee, Employee superior, int monthlySaleryCents) {}
Records like these can be matched as follows:
String getEmployeeInfo(Employee e){
return switch(e) {
case Employee(Person(String firstName, String lastName, _), Employee(Person(String bossFirstName, String bossLastName, _), Employee bossOfBoss, _), int salery) -> firstName + " " + lastName + " earns " + salery/100 + "€ per month and their boss is " + bossFirstName + " " + bossLastName;
case Employee(Person(String firstName, String lastName, _), Employee boss, int salery) when boss == null -> firstName + " " + lastName + " earns " + salery/100 + "€ per month and is their own boss";
};
}
String getEmployeeInfo(Employee e){
return switch(e) {
case Employee(Person(String firstName, String lastName, _), Employee(Person(String bossFirstName, String bossLastName, _), Employee bossOfBoss, _), int salery) -> firstName + " " + lastName + " earns " + salery/100 + "€ per month and their boss is " + bossFirstName + " " + bossLastName;
case Employee(Person(String firstName, String lastName, _), Employee boss, int salery) when boss == null -> firstName + " " + lastName + " earns " + salery/100 + "€ per month and is their own boss";
};
}
Employee boss = new Employee(new Person("Sara","Huber",LocalDate.of(1980,1,1)), null, 5_400_00);
Employee maxInCompany = new Employee(max, boss, 3_800_00);
System.out.println(getEmployeeInfo(maxInCompany));
System.out.println(getEmployeeInfo(boss));
Employee boss = new Employee(new Person("Sara","Huber",LocalDate.of(1980,1,1)), null, 5_400_00);
Employee maxInCompany = new Employee(max, boss, 3_800_00);
System.out.println(getEmployeeInfo(maxInCompany));
System.out.println(getEmployeeInfo(boss));
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre3w ago
If looked at in terms of objects, a record is a value object with fields that are implicitly final, and several pre-generated methods, such as equals and hashCode that make sense for comparing records. The more likely answer, if viewing the question from the point of view of pattern matching, is the use of instanceof to cast an object to a record type and use the fields of that record implicitly. This can even be done recursively. Example below: Foo.java
public record Foo(int value) {
}
public record Foo(int value) {
}
Bar.java
public record Bar(Foo foo) {
}
public record Bar(Foo foo) {
}
Main.java
public static void main() {
Foo foo = new Foo(42);

if (foo instanceof Foo(int value)) {
System.out.println("value = " + value); // implicit use of value defined in foo above
}

Bar bar = new Bar(foo);
if (bar instanceof Bar( Foo(int value) )) {
System.out.println("value = " + value); // use of value through recursive record pattern matching
}
}
public static void main() {
Foo foo = new Foo(42);

if (foo instanceof Foo(int value)) {
System.out.println("value = " + value); // implicit use of value defined in foo above
}

Bar bar = new Bar(foo);
if (bar instanceof Bar( Foo(int value) )) {
System.out.println("value = " + value); // use of value through recursive record pattern matching
}
}
Submission from awesomealec1

Did you find this page helpful?