Карта / ООП / Pattern matching

Pattern matching

Pattern matching — возможность проверить тип и сразу получить переменную этого типа без лишнего кастинга. Появился в Java 16 (instanceof), расширен в Java 21 (switch).

До Java 16 — проверка и каст вручную:

if (obj instanceof String) {
    String s = (String) obj;  // кастим отдельно — дублирование
    System.out.println(s.length());
}

Java 16+ — pattern matching для instanceof:

if (obj instanceof String s) {  // проверяет И сразу объявляет переменную s
    System.out.println(s.length());
}

Java 21 — pattern matching в switch:

Object obj = getValue();
String result = switch (obj) {
    case Integer i -> "Число: " + i;
    case String s  -> "Строка длиной " + s.length();
    case null      -> "null";
    default        -> "Что-то другое";
};

Guarded patterns — условие прямо в case:

switch (shape) {
    case Circle c when c.radius() > 100 -> "Большой круг";
    case Circle c                        -> "Маленький круг";
    case Rectangle r                     -> "Прямоугольник";
}
Копнуть глубже

Exhaustiveness (полнота) — главная сила в связке с sealed. Если переключаемся по sealed типу — компилятор требует покрыть все варианты. Забыли один case → ошибка компиляции, а не NPE в рантайме:

sealed interface Notification permits Email, Push, SMS {}

// Компилятор не даст скомпилировать если забыть один из трёх case
String format(Notification n) {
    return switch (n) {
        case Email e -> "Email: " + e.address();
        case Push p  -> "Push: " + p.deviceId();
        case SMS s   -> "SMS: " + s.phone();
    };
}

Деконструкция record (Java 21). Pattern matching умеет «распаковывать» record прямо в switch:

record Point(int x, int y) {}

Object obj = new Point(3, 4);
if (obj instanceof Point(int x, int y)) {  // деконструкция
    System.out.println(x + ", " + y);       // сразу x и y без геттеров
}

Порядок case важен. Более специфичные паттерны должны стоять выше общих — иначе компилятор ошибка «доминирование паттерна»:

switch (s) {
    case Circle c when c.radius() > 0 -> ...  // ✅ сначала частный случай
    case Circle c -> ...                       // ✅ потом общий
}
// Наоборот — ошибка компиляции: второй case никогда не достигается
🎤 Закрыл тему, если можешь объяснить:
• как pattern matching для instanceof упрощает работу с типами;
• что такое guarded patterns и почему sealed + switch обеспечивают exhaustiveness (если дошёл до 2-го слоя).