Pattern мatching. record-паттерн

Последнее обновление: 27.09.2025

Начиная с версии Java 21 мы можем использовать так называемый record pattern - паттерн, который позволяет проверить на соответствие типу классу record и использовать его поля. Для применения паттерна record можно применять как оператор instanceof, так и конструкции/выражения switch.

instanceof

Пример record patter с применением оператора instanceof:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom", 22);

        if(tom instanceof Person(var pName, var pAge)){
            System.out.printf("Person. Name: %s;  Age: %d\n", pName, pAge);
        }
    }
}
record Person(String name, int age){}

В данном случае с помощью выражения tom instanceof Person(var pName, var pAge) мы не только проверяем, что переменная tom представляет тип Person, но и объявляем переменные name и age, которые получают значения одноименных полей класса Person. Затем внутри блока if мы можем использовать эти переменные.

Причем мы явным образом можем указать тип переменных

if(tom instanceof Person(String pName, int pAge)){
    System.out.printf("Person. Name: %s;  Age: %d\n", pName, pAge);
}

Если нам какое-то поле не нужно, мы можем его опустить и вместо переменной указать прочерк. Например, нам нужно только поле age:

if(tom instanceof Person(_, int pAge)){
    System.out.printf("Person Age: %d\n", pAge);
}

switch

Конструкции/выражения switch также позволяют использовать данный паттерн:

Person tom = new Person("Tom", 22);

switch(tom){

    case Person(var pName, var pAge) ->
        System.out.printf("Person. Name: %s;  Age: %d\n", pName, pAge);

    case null -> System.out.printf("Undefined");
}

Константы и защитные условия guards

Стоит учитывать, что в record pattern мы не можем использовать константы. Напимер, нам нужно отдельно отследить ситуацию, когда имя пользователя - "Tom". Но мы не можем написать так:

if(tom instanceof Person("Tom", _)){  // Ошибка: "Tom" - константа
    System.out.printf("Person Tom");
}

Однако мы можем использовать защитные условия, где переменные сравниваются с определенными константами:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom", 22);
        Person bob = new Person("Bob", 46);

        printPerson(tom);       // Hello Tom
        printPerson(bob);       // Hello
    }

    static void printPerson(Person person){

        if(person instanceof Person(var pName, _) && pName == "Tom"){
             System.out.println("Hello Tom");
        }
        else if(person instanceof Person(_, _) ){
             System.out.println("Hello");
        }
    }
}

Таким образом, если имя "Tom", то срабатывает блок if:

if(person instanceof Person(var pName, _) && pName == "Tom"){
    System.out.println("Hello Tom");
}

Если же у пользователя другое имя, то срабатывает блок else if

else if(person instanceof Person(_, _) ){
    System.out.println("Hello");
}

При использовании switch для создания защитных условий применяется оператор when, после которого идет условие:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom", 22);
        Person bob = new Person("Bob", 46);

        printPerson(tom);       // Hello Tom
        printPerson(bob);       // Hello
    }

    static void printPerson(Person person){

        switch(person){

            case Person(var pName, _)  when pName == "Tom" -> // только для тех Person, где name = "Tom"
                System.out.println("Hello Tom");

            case Person(_, _) ->                // для всех остальных Person
                System.out.println("Hello");

            case null -> {}   // если null, ничего не выводим
        }
    }
}

Вложенные шаблоны

Шаблоны могут быть вложенными:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom", 41);
        Company mycorp = new Company("MyCorp", tom);

        if(mycorp instanceof Company(_, Person(var name, _))){
            System.out.println("CEO: " + name);
        }
    }
}
record Person(String name, int age){}
record Company(String name, Person ceo){}

В данном случае второе поле класса Company представляет тип Person. А с помощью выражения mycorp instanceof Company(_, Person(var name, _)) получаем поле name у класса Person в одноименную переменную name.

Аналогичный пример с switch:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom", 41);
        Company mycorp = new Company("MyCorp", tom);

        switch(mycorp){

            case Company(_, Person(var name, _)) ->
                System.out.println("CEO: " + name);

            case null -> {}
            default -> {}
        }
    }
}
record Person(String name, int age){}
record Company(String name, Person ceo){}

Обратите внимание на последние два блока сопоставления:

case null -> {}
default -> {}

При определении конструкции следует учитывать, что варианты в ней должны быть "exhaustive" (исчерпывающими), то есть охватывать все возможные варианты. В нашем случае у нас компания может быть равна null:

Company mycorp = null;

Этот вариант отслеживается блоком

case null -> {}

Однако у нас может быть вариант, что Person равен null:

Company mycorp = new Company("MyCorp", null);

Этот вариант отслеживается блоком default, который отслеживает все остальные варианты:

default -> {}
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850
Morty Proxy This is a proxified and sanitized view of the page, visit original site.