Получить доступ

Sealed-типы и pattern matching

Закрытые иерархии через sealed, pattern matching в instanceof и switch, деконструкция записей и проверка исчерпываемости.

Sealed-типы

sealed class/interface (Java 17) ограничивает список наследников через permits: только перечисленные типы могут расширять/реализовывать его. Каждый разрешённый подтип обязан быть final, sealed или non-sealed (явно «открыт снова»).

Зачем: закрытая иерархия домена (алгебраический тип) — компилятор ЗНАЕТ полный набор вариантов. Это даёт исчерпывающие проверки и точную модель: PaymentResult — это ровно {Ok, Failed}, и третьего не дано.

sealed interface PaymentResult permits PaymentOk, PaymentFailed {}
record PaymentOk(String id) implements PaymentResult {}
record PaymentFailed(String reason) implements PaymentResult {}

Pattern matching в instanceof

Pattern matching for instanceof убирает ручной cast: if (o instanceof String s) сразу связывает переменную s нужного типа, если проверка прошла.

Работает flow scoping: переменная-паттерн видна только там, где компилятор доказал её тип (например, в then-ветке, или после раннего return в else). Это и короче, и безопаснее, чем instanceof + явный cast.

if (obj instanceof String s && !s.isBlank()) {
    use(s); // s уже String, без приведения
}

switch с паттернами и исчерпываемость

switch умеет ветвиться по типу: case PaymentOk ok -> …, case PaymentFailed f -> …. Для sealed-типа компилятор проверяет ИСЧЕРПЫВАЕМОСТЬ: если покрыты все разрешённые варианты, default не нужен. И наоборот — добавите новый подтип в sealed-иерархию, и компилятор заставит обработать его во всех таких switch (ошибка компиляции вместо тихого пропуска).

Условия уточняют guarded-паттерны: case Integer i when i > 0. Это превращает switch в полноценный разбор вариантов, как match в функциональных языках.

String describe(PaymentResult r) {
    return switch (r) {                 // default не нужен — sealed исчерпан
        case PaymentOk ok -> "ok: " + ok.id();
        case PaymentFailed f -> "fail: " + f.reason();
    };
}

Деконструкция записей

Record patterns (Java 21) распаковывают запись прямо в паттерне: case Point(int x, int y) -> … достаёт компоненты в переменные. Деконструкция вкладывается: case Line(Point(var x1, var y1), Point(var x2, var y2)).

Связка sealed + record + switch с деконструкцией — это и есть алгебраические типы данных в Java: компактный, типобезопасный и исчерпывающий разбор формы данных.

null в switch

Историческая ловушка: обычный switch бросал NullPointerException на null. В switch с паттернами это лечится явной веткой case null (иначе поведение прежнее).

Как отвечать на собеседовании

Объясните sealed как закрытую иерархию (компилятор знает все варианты → исчерпываемость), pattern matching в instanceof (без cast, flow scoping) и switch по типам с проверкой полноты для sealed, и покажите деконструкцию record как вершину — алгебраические типы. Подчеркните выгоду: добавление варианта ловится компилятором во всех switch.

Вопросы по теме

Читайте также

Закрытая бета

Знать тему — половина дела

На живом собеседовании sotto слышит вопрос интервьюера и показывает короткий ответ и план. Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем