Record Patterns in Java

Pattern Matching is a new area where Java has been introducing quite a few changes recently.

It started with instanceof operator.

Previously in Java , if you had to access an object whose instance type you didnt know prior, you had to use instanceof operator this way:

if (obj instanceof String) {
    String s = (String)obj;
     // use s here
}

You had to do a cast operation as shown above.

Java then got rid of the cast and allowed you to put the reference variable along with the statement including instanceof operator like this:

if (obj instanceof String s) {
 //use s here
}

No casting!

And less number of code.

Java internally matched the pattern and assigned the object to the reference variable.

This was extended to records.

Like the below example:

record Position(int xCoordinate, int yCoordinate) {}

static void printSum(Object object) {
    if (object instanceof Position position) {
        int xCoordinate = position.xCoordinate();
        int yCoordinate = position.yCoordinate();
        int sum = xCoordinate + yCoordinate;
        System.out.println("The sum of x and y coordinates is: " + sum);
    }
}

As you see , the record Position is assigned a reference variable “position” directly in the if statement.

The position object can then be accessed inside the if loop directly.

Java further improved the above code for records.

Starting Java 20 , You can remove the reference variable altogether and still be able to access the fields of the record object:

record Position(int xCoordinate, int yCoordinate) {}

void printSum(Object obj) {
    if (obj instanceof Position(int xCoordinate, int yCoordinate)) {
        System.out.println(xCoordinate+yCoordinate);
    }
}

There is no need of a reference variable to the Position record to access its fields!

This also applies to nested records:

record Company(String name, Employee e){}
record Employee(String name, Role role){}
record Role(String name , Department department){}
record Department(String name)


void printDepartment(Object obj){

        if(obj instanceof Company(String name , Employee(String name, Role(String name , Department(String name)))){
                   System.out.println("Department name is "+name);
   }
} 
}

As you see “Company” is a record which contains a nested record “Employee” which contains a nested record “Role” which contains a nested record “Department” which contains a field named “name”.

And we can directly access the name field value using Pattern Matching!

Record Patterns in Enhanced For loop:

Just like in instanceof operator , pattern matching can be applied now inside enhanced for loops as well.

Consider the below example:

Before:

record Person(String name, int age) {}

static void print(Person[] persons) {
    for (Person p : persons) {        
        System.out.println("(" + p.name+ ": " + p.age + ")");
    }
}

Now:


record Person(String name, int age) {}

static void print(Person[] persons) {
    for (Person(var name, var age) : persons) {        
        System.out.println("(" + name+ ": " + age + ")");
    }
}

As you see instead of creating a reference variable for the Person record in the enhanced for loop and accessing the variables of the record using that reference variable , we are directly accessing the variable names inside the for loop.

Parameterized vs Raw Types:

If a record class is generic , then it can be used in a record pattern as a raw type or a parameterized type.

Consider the below code :

record Person<T>(T t) {}

static void test(Person<String> p) {
    if (p instanceof Person<String>(var s)) {
        System.out.println("Name" + s);
    }
}

It uses parameterized type using the < > symbol.

It can also be written as :

record Person<T>(T t) {}

static void test(Person<String> p) {
    if (p instanceof Person(var s)) {
        System.out.println("Name" + s);
    }
}

That’s it!


Posted

in

, ,

by

Comments

Leave a Reply

%d bloggers like this: