Сопоставление с образцом (Pattern Matching) — новая превью функция в Java 14.


instanceof


Чтобы лучше понять эту новую функцию, давайте посмотрим, как работает оператор instanceof. Если вы уже знакомы с ним, не стесняйтесь переходить к следующему разделу.


Короче говоря, он проверяет, принадлежит ли данный объект заданному типу. В результате этой проверки он возвращает либо true, либо false.


    if(animal instanceof Cat) {
      // It is a cat! Do something
    } else {
      // It is not a cat, do something else
    }

Этот оператор возвращает true, если ваш объект имеет данный тип или его подтип. В противном случае возвращается false.


Соответствие шаблону для instanceof


Старый добрый способ


Рассмотрим следующий пример. Animal — это класс, который имеет два подкласса: Cat и Dog.


public String getAnimalSound(Animal animal) {
    if(animal instanceof Cat) {
        Cat cat = (Cat)animal;
        return cat.meow();
    } else if (animal instanceof Dog) {
        Dog dog = (Dog)animal;
        return dog.bark();
    }
    throw new UnknownAnimalException();
}

Мы получаем объект animal на входе. Если объект animal является экземпляром класса Cat, мы хотим, чтобы этот объект говопил «мяу». Если это объект Dog, нам нужно чтобы он лаял. Поскольку этих методов нет в классе Animal, но они есть его подклассах, нам необходимо:


  1. Во-первых, проверить, какой тип объекта animal у нас есть, используя instanceof.
  2. Создать новую переменную типа Cat или Dog.
  3. Привести объект animal к правильному типу.

Теперь мы можем использовать наш объект Cat или Dog. Варианты использования этого могут быть довольно разнообразными.


Код выполняет свою работу, но он излишне многословен. Нам обычно нужно сделать все шаги перечисленные выше. Преобразовние типа объекта не нужно, так как мы уже проверили, что у нас есть либо Cat или Dog.


К счастью, в Java 14 появилась новая функция под названием Сопоставление с образцом для instanceof, описанная в JEP 305. В настоящее время это превью функция, поэтому она может измениться в будущем выпуске.


Лучший способ


В Java 14 приведенный выше пример может быть упрощен.


// Before Java 14
if(animal instanceof Cat) {
    Cat cat = (Cat)animal;
    return cat.meow();
}

//After
if(animal instanceof Cat cat) {
    return cat.meow();
}

Вот что изменилось:


  1. Не нужно объявлять переменную cat, она доступна для нас.
  2. Не нужно преобразование типа. Мы можем использовать cat, как если бы она была типа Cat.
  3. Область действия переменной cat находится только внутри блока if.

Это проще, лаконичнее, легче для чтения и менее подвержено ошибкам.


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


Как уже упоминалось, область действия переменной ограничена только блоком if:


if(animal instanceof Cat cat) {
    return cat.meow();
} else {
    // Can't use cat here
}
// Can't use cat here either

Однако, вы можете использовать переменную внутри условия if, если у вас есть более сложные условия, такие как AND/OR.


if(animal instanceof Cat cat && cat.isAlive()) {
    return cat.meow();
}

После проверки instanceof, после &&, мы можем использовать переменную cat, уже имеющую тип Cat, а не Animal.


Поддержка IDEA


Хорошей новостью является то, что в IntelliJ IDEA появилась хорошая поддержка этой функции, представленная в версии 2020.1 (наряду с поддержкой других новых функций Java 14, таких как Records или Улучшенный Switch).



Попробуй сам!


Чтобы попробовать эту функцию самостоятельно, вам нужно установить JDK 14.


Функция превью


Сопоставление с образцом для instanceof функциональности доступно в Java 14. Однако в настоящее время только в качестве функции превью (Preview feature). Что это значит?


Превью возможности языка и VM — это новая функция платформы Java SE, которая полностью специфицирована, реализована, но в то же время определена как временная. Она включается в выпуск JDK для получения обратной связи с разработчиками на основе реального использования; это может привести к тому, что она станет постоянной в будущей платформе Java SE.

Перед следующим выпуском функции JDK будут проанализированы сильные и слабые стороны функции в реальном мире, чтобы решить, имеет ли функция долгосрочную роль в платформе Java SE и, если да, нуждается ли она в уточнении. Следовательно, функции могут быть предоставлены окончательный и постоянный статус (с уточнениями или без них), или пройти дополнительный период предварительного просмотра (с уточнениями или без них), либо они могут быть удалены.

Такие функции поставляются в JDK, но не включены по умолчанию. Вы должны явно разрешить им использовать их. Излишне говорить, что она предназначена не для производственного использования, а скорее для оценки и экспериментов, поскольку она может быть удалена или сильно изменена в будущем выпуске.


Настройка IntelliJ IDEA


В IntelliJ IDEA вы можете включить функции предварительного просмотра в меню File > Project Structure.



Ручная компиляция


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


javac --release 14 --enable-preview ...

Это для компиляции. Во время выполнения вы просто задаете параметр --enable-preview


java --enable-preview ...

Maven проекты


Для сборок Maven вы можете использовать следующую конфигурацию:


<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <release>14</release>
                <compilerArgs>
                    --enable-preview
                </compilerArgs>
```14</source>
                <target>14</target>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <argLine>--enable-preview</argLine>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <configuration>
                <argLine>--enable-preview</argLine>
            </configuration>
        </plugin>
    </plugins>
</build>

Также новое в Java 14


Records
Enhanced Switch
Text Blocks