Writing Less Boilerplate Code in Java 19 With Instanceof and Record Classes Thanks to Record Patterns

Info

This post is part of a blog post series titled 6 New Features in Java 19 That Make Your Life Easier.

Note

This is a preview feature. In order to use it, compile the program with javac --release 19 --enable-preview Main.java and run it with java --enable-preview Main. More details about using preview features in your project can be found here.

In JDK 16, the instanceof operator was extended to accept a type pattern and perform pattern matching. Thanks to this, the instanceof-and-cast idiom could be simplified. Instead of writing

if (o instanceof String) {
    String s = (String) o;
    ... use s ...
}

developers can write

if (o instanceof String s) {
    ... use s ...
}

If the pattern matches, the pattern variable s is initialized to the value of o cast to String. s can then be used in the contained code block. That’s super convenient.

The same is now possible for record classes. Let’s assume we want to check whether a value is an instance of a record class Point and if so, use the components of Point in the contained code block. We can simply write:

record Point(int x, int y) {}

static void printSum(Object o) {
    if (o instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
} 

We can even go one step further and let Java extract the components for us so that we can use them straight away in the containing code block:

record Point(int x, int y) {}

void printSum(Object o) {
    if (o instanceof Point(int x, int y)) {
        System.out.println(x + y);
    }
}

In the previous example, Point(int x, int y) represents a record pattern that contains the declaration of the local variables and initializes them automatically by calling the access methods. That’s really cool and much less boilerplate code. Awesome!

But wait, there’s more! Pattern matching also works for nested instances of record classes:

record Point(int x, int y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}

static void printColorOfUpperLeftPoint(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point p, Color c), ColoredPoint lr)) {
        System.out.println(c);
    }
}

Nested record patterns thus allow us to easily access the data expressed by complex objects. this feature is really handy and will save us from typing a lot of unnecessary code in the future.

References

Leave a Comment

Your email address will not be published. Required fields are marked *