Статьи

JDK 14 / JEP 305 экземпляр сопоставления с образцом «Smart Casts»

Я обычно рассматриваю присутствие оператора instanceof в коде Java как « красный флаг », означающий, что использование instanceof в определенных ситуациях не обязательно является неправильным, но его использование иногда указывает на проблему проектирования, которая может быть решена более чистым способом, как описано в некоторых ресурсах, упомянутых в конце этого поста (в том числе в ресурсах о похожих функциях проверки типов в языках, отличных от Java).

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

Очень распространенная техника, используемая с instanceof заключается в немедленном приведении к типу, проверенному в условном использовании instanceof . JEP 305 [«Сопоставление с образцом для instanceof (Preview)»] предоставляет пример этого общего образца, и я немного адаптировал этот пример здесь:

1
2
3
4
5
if (object instanceof String)
{
    final String string = (String) object;
    // Do something with the 'string' variable typed as String
}

Бенджи Вебер писал о том, как использовать отражение и использовать лямбда-выражения для создания «экземпляров умных бросков», подобных котлинскому . К счастью, JDK 14 и JEP 305 имеют встроенную языковую поддержку (хотя и статус предварительного просмотра) для этого подхода.

JDK 14 представляет функцию предварительного просмотра, которая позволяет полностью реализовать instanceof условного и связанного преобразования в условном выражении. Эффект на приведенном выше примере кода показан ниже:

1
2
3
4
if (object instanceof String string)
{
    // Do something with the 'string' variable typed as String
}

Эта функция предварительного просмотра доступна в ранних сборках JDK 14, и я использую JDK 14 раннего доступа 34 для моих примеров в этом посте.

Функция предварительного просмотра JEP 305 в JDK 14 — это небольшая хитрость, преимущество которой более очевидно в длинных условных выражениях ifthenelse . Следующие два листинга кода обеспечивают сравнение «старого способа» вызова instanceof и явного приведения к «новому способу предварительного просмотра» использования instanceof сопоставления с образцом .

Традиционный instanceof сочетании с явным приведением

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
static void makeAnimalNoises(final Object animal)
{
   if (animal instanceof Dog)
   {
      final Dog dog = (Dog) animal;
      out.println(dog.bark());
   }
   else if (animal instanceof Cat)
   {
      final Cat cat = (Cat) animal;
      out.println(cat.meow());
   }
   else if (animal instanceof Duck)
   {
      final Duck duck = (Duck) animal;
      out.println(duck.quack());
   }
   else if (animal instanceof Horse)
   {
      final Horse horse = (Horse) animal;
      out.println(horse.neigh());
   }
   else if (animal instanceof Cow)
   {
      final Cow cow = (Cow) animal;
      out.println(cow.moo());
   }
   else if (animal instanceof Lion)
   {
      final Lion lion = (Lion) animal;
      out.println(lion.roar());
   }
   else
   {
      out.println("ERROR: Unexpected animal: " + animal);
   }
}

Предварительный просмотр JDK 14 / JEP 305

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static void makeAnimalNoises(final Object animal)
{
   if (animal instanceof Dog dog)
   {
      out.println(dog.bark());
   }
   else if (animal instanceof Cat cat)
   {
      out.println(cat.meow());
   }
   else if (animal instanceof Duck duck)
   {
      out.println(duck.quack());
   }
   else if (animal instanceof Horse horse)
   {
      out.println(horse.neigh());
   }
   else if (animal instanceof Cow cow)
   {
      out.println(cow.moo());
   }
   else if (animal instanceof Lion lion)
   {
      out.println(lion.roar());
   }
   else
   {
      out.println("ERROR: Unexpected animal: " + animal);
   }
}

Полный код находится на GitHub, и есть разница между старым подходом и новым подходом предварительного просмотра .

Поскольку instanceof сопоставление с образцом является функцией предварительного просмотра, код, использующий эту функцию, должен быть скомпилирован с флагами javac --enable-preview и -source 14 . Это должно быть выполнено с флагом Java --enable-preview .

Вывод

Для получения более подробной информации о том, как реализована эта функция, см. Пост « RFR: JDK-8237528: Неэффективная компиляция сопоставления с образцом для instanceof ». Поддержка сопоставления с образцом для instanceof — это еще один шаг Amber к сокращенному шаблонному коду в Java.

Ресурсы по вопросам использования instanceof

Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG . См. Оригинальную статью здесь: JDK 14 / JEP 305 instanceing Pattern Matching «Smart Casts»

Мнения, высказанные участниками Java Code Geeks, являются их собственными.