92. Introducing record pattern for instanceof
In order to introduce record patterns we need a record, so here is one:
public record Doctor(String name, String specialty)
implements Staff {}
This record implements the Staff interface as any other employee of our hospital. Now, we can identify a certain doctor in the old-fashion style via instanceof as following:
public static String cabinet(Staff staff) {
if (staff instanceof Doctor) {
Doctor dr = (Doctor) staff;
return “Cabinet of ” + dr.specialty()
+ “. Doctor: ” + dr.name();
}
…
}
But, as we know from Chapter 2, Problems x-y, JDK has introduced type patterns that can be used for instanceof and switch. So, in this particular case, we can rewrite the previous code via type patterns as follows:
public static String cabinet(Staff staff) {
if (staff instanceof Doctor dr) { // type pattern matching
return “Cabinet of ” + dr.specialty()
+ “. Doctor: ” + dr.name();
}
…
}
Nothing is new so far! The binding variable dr can be used to call the record accessor’s specialty() and name(), to add checks, computations, and so on. But, the compiler knows very well that the Doctor record was built based on two components (name and specialty) so the compiler should be able to deconstruct this object and to give us directly these components as binding variables instead of accessing them via dr.This is exactly what record pattern matching is all about. Record pattern matching occurred as a preview feature in JDK 19 (JEP 405) and as a second preview feature in JDK 20 (JEP 432).Record pattern matching is exactly the syntax of declaring name and specialty as binding variables by following the same declaration syntax as in the record itself (or like in the canonical constructor). Here is the previous code written via record patterns:
public static String cabinet(Staff staff) {
// record pattern matching
if (staff instanceof Doctor(String name, String specialty)){
return “Cabinet of ” + name + “. Doctor: ” + specialty;
}
…
}
Very simple, isn’t it?Now, the name and specialty are the binding variables that can be used directly. We simply put this syntax in place of the type pattern. In other words, we replaced the type pattern with a record pattern.
The compiler exposes the record’s components via the corresponding binding variables. This is accomplished by deconstructing records in pattern matching which is referred to as record patterns. In other words, the deconstruction patterns allow us to access the components of an object in a very handy, intuitive, and readable way.
Of course, if you need the dr binding variable (so, a reference to the record itself) next to the name and specialty binding variables then simply added as follows:
public static String cabinet(Staff staff) {
if (staff instanceof
Doctor(String name, String specialty) dr) {
return “Cabinet of ” + specialty + “. Doctor ID: “
+ dr.hashCode() + ” (” + name + “)”;
}
…
}
This is really cool!