В прошлый раз мы обсудили pattern matching в вакууме. Сегодня обсудим, как он выглядит в java с учётом 21 версии, и чего не хватает в текущей реализации.
Под зонтик pattern matching относят много фич: sealed классы, records, обновление switch и instanceOf. Sealed и records в контексте pattern matching — специфичные кейсы data oriented programming, не будем о них. Cфокусируемся на более популярных сценариях:)
Итак, как pattern matching воплощается в синтаксисе:
1️⃣ Компактный instanceOf
Раньше для неизвестного типа выполнялись две операции: instanceOf и явное приведение типа:
if (obj instanceof String) {
String str = (String) obj;
// используем str
}
Теперь эти операции объединены. Рядом с instanceOf объявляем имя переменной и сразу ей пользуемся:if (obj instanceof String str) {
// используем str
}
Тонкий момент— переменная определяется только при успешном выполнении instanceOf, поэтому есть нюанс с областью видимости.В логическом И можно использовать переменную в том же if:
✅
if (obj instanceof String s && s.length() > 5)
Логическое ИЛИ такого не позволяет, будет ошибка компиляции:❌
if (obj instanceof String s || s.length() > 5)
2️⃣ Компактный switchУ древнейшей конструкции доступен новый синтаксис:
▫️ Стрелочка вместо двоеточия
▫️ Break в конце case по умолчанию, и его можно не писать
▫️ Можно объединить несколько case в один
Старый синтаксис никуда не делся, им можно пользоваться:
switch (value) {
case 1:
case 3: println("Odd"); break;
case 2:
case 4: println("Even"); break;
default: println("Other");
}
В "новом стиле" это будет так:switch (value) {
case 1,3 -> println("Odd");
case 2,4 -> println("Even");
default -> println("Other")
}
Важный момент — break добавляется по умолчанию только в вариант "со стрелочками". В "двоеточиях" break всё ещё добавляется вручную.🔥 Ответ на вопрос перед постом: выведется
Even Other Even. Чтобы работало как надо, нужно переписать на стрелочки или добавить break.3️⃣ Присвоение элемента через switch
int value = switch(…) {…};
4️⃣ Проверка в switch по типам и сложные caseРаньше в case принимались только константы. Теперь можно проверить тип переменной:
switch (obj) {
case Integer i -> …
case Long l -> …
case Double d -> …
}
Если произошёл мэтч, для переменной сразу доступна доп. информация, и можно добавить условия в case:switch (response) {
case String s when s.length() == 10 -> …
}
А теперь самое интересное! Обсудим, чего в текущей реализации нет: ❌ Нет работы с массивами
Один из кейсов pattern matching — работа с набором данных, в которых мы ищем определённые признаки. Такого в java пока нет:
double discount = switch(transaction) {
case ["vip", Long, _, _, Double sum] → sum*0,9
case _ → 0
}
В других языках такой функционал есть. Например, List patterns в С# или Matching sequences в питоне.❌ Нет паттернов по полям класса
Под капот спрятан только instanceOf, остальные условия выглядят как в обычном if. Вся работа с полями происходит через методы:
switch (figure) {
case Square s when s.getLength() != 10 → …
}
В том же питоне запись гораздо компактнее:match point:JEP Record Patterns мог быть как раз об этом, ведь records позиционируются как лаконичные контейнеры данных. Но увы.
case (0, 0): …
case (0, y): …
case _: …
Резюме
В текущем виде pattern matching выглядит слабо, особенно по сравнению с другими языками. Покрыты только базовые кейсы, в таком виде область применения очень ограничена.
Возможно это лишь промежуточный этап. Посмотрим, как фича будет развиваться и использоваться✨