Особенности sealed

Sealed классы и интерфейсы в Kotlin предоставляют способ ограничить иерархию классов, что позволяет вам четко контролировать, какие подклассы могут быть созданы. Это особенно полезно при работе с исчерпывающими when-выражениями, где компилятор может проверять, все ли возможные случаи рассмотрены.

Особенности sealed классов и интерфейсов

  1. Ограничение подклассов: Подклассы sealed класса или интерфейса могут быть объявлены только в том же файле, что и сам sealed класс или интерфейс. Это ограничение позволяет компилятору знать все возможные подклассы, что упрощает обработку в when-выражениях.

  2. Исчерпывающее when-выражение: Благодаря знанию всех возможных подклассов, компилятор может обеспечить, что вы рассматриваете все случаи в when-выражении, избегая ошибок времени выполнения.

  3. Поддержка данных и вложенных типов: Sealed классы могут содержать объекты данных, которые позволяют создавать удобные представления состояний с различными параметрами.

Преимущества sealed классов и интерфейсов

  1. Компиляторная поддержка: Компилятор может проверить, что вы рассматриваете все возможные случаи в when-выражениях.
  2. Четкость и безопасность: Поскольку все возможные подклассы известны и контролируются, код становится более предсказуемым и безопасным.
  3. Удобство работы с состояниями: Sealed классы и интерфейсы удобно использовать для представления различных состояний, что особенно полезно в конечных автоматах и реактивных приложениях.

Под капотом

Под капотом sealed классы компилируются в абстрактные классы, и каждый подкласс хранится в том же файле. Компилятор добавляет проверки для обеспечения того, что подклассы не могут быть объявлены вне файла, содержащего sealed класс или интерфейс.

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val exception: Throwable) : Result()
    object Loading : Result()
}

fun handleResult(result: Result) {
    when (result) {
        is Result.Success -> println("Data: ${result.data}")
        is Result.Error -> println("Error: ${result.exception.message}")
        is Result.Loading -> println("Loading...")
    }
}
// Пример скомпилированного кода на Java для sealed класса Result
public abstract class Result {
    private Result() {}

    public static final class Success extends Result {
        private final String data;

        public Success(String data) {
            this.data = data;
        }

        public String getData() {
            return data;
        }
    }

    public static final class Error extends Result {
        private final Throwable exception;

        public Error(Throwable exception) {
            this.exception = exception;
        }

        public Throwable getException() {
            return exception;
        }
    }

    public static final class Loading extends Result {
        public static final Loading INSTANCE = new Loading();

        private Loading() {}
    }
}