Библиотека джависта | Java, Spring, Maven, Hibernate
23.5K subscribers
2.18K photos
44 videos
45 files
3.07K links
Все самое полезное для Java-разработчика в одном канале.

Список наших каналов: https://t.iss.one/proglibrary/9197

Для обратной связи: @proglibrary_feeedback_bot

По рекламе: @proglib_adv

РКН: https://gosuslugi.ru/snet/67a5bbda1b17b35b6c1a55c4
Download Telegram
🔍 Просто о сложном: Sealed Classes

В Java 17 появились Sealed Classes — механизм явного контроля иерархии наследования. Теперь можно точно указать, какие классы могут наследоваться от вашего типа.

По сути, это золотая середина между публичными классами (наследовать может кто угодно) и final классами (наследовать нельзя вообще). Вы сами решаете, кто входит в "белый список" наследников.

🔹 Зачем они нужны

Обычное наследование имеет проблемы:

— невозможно гарантировать закрытость иерархии (кто-то может добавить свой подтип);
— компилятор не может проверить, что все случаи покрыты (switch требует default, даже если вы обработали все варианты);
— сложно моделировать ADT (Algebraic Data Types) из функционального программирования.

Sealed классы решают эти проблемы: компилятор знает все возможные подтипы и может проверить полноту обработки в pattern matching.

🔹 Ключевые моменты

▪️ sealed — ключевое слово для объявления запечатанного класса/интерфейса.
▪️ permits — явное перечисление разрешённых наследников.
▪️ Наследники должны быть: final, sealed, или non-sealed.
▪️ Если наследники в том же файле, permits можно опустить.
▪️ Отлично работает с pattern matching и switch expressions.

public sealed interface Result<T> 
permits Success, Failure {
}

public final record Success<T>(T value)
implements Result<T> {}

public final record Failure<T>(String error)
implements Result<T> {}


🔹 Под капотом


Компилятор создаёт специальный атрибут PermittedSubclasses в bytecode, который содержит список разрешённых наследников. При загрузке класса JVM проверяет, что все указанные подклассы действительно существуют и корректны.

Pattern matching с sealed types позволяет компилятору проверить полноту покрытия без default ветки:
return switch(result) {
case Success(var value) -> process(value);
case Failure(var error) -> handleError(error);
};


🔹 Подводные камни

— Обратная совместимость
Если вы сделали класс sealed в новой версии библиотеки, старый код с кастомными наследниками перестанет компилироваться.

— Видимость подклассов
Все наследники должны быть доступны sealed классу на момент компиляции. Нельзя добавить подкласс из другого модуля или jar.

— Сериализация
При десериализации sealed иерархии нужна осторожность? можно получить подделанный подтип. Используйте validation или sealed интерфейсы с records.

— non-sealed подклассы
Если сделать наследника non-sealed, он открывает дыру в иерархии и от него можно наследоваться кому угодно. Используйте осторожно.

✔️ Когда использовать

— Моделирование состояний (State machines, FSM).
— Result/Either типы для обработки ошибок без exceptions.
— Domain-driven design с явными типами (Payment может быть Card, Cash, Crypto).
— Pattern matching в бизнес-логике с гарантией полноты.
— API, где важно контролировать расширяемость.

Не подходит:

— Публичные библиотеки с plugin-архитектурой.
— Когда нужна расширяемость от пользователей.
— Legacy код с активным использованием наследования.
— Простые entity/DTO классы без полиморфизма.

🐸 Библиотека джависта

#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍43👏1