0Pricing
Java Academy · Урок

Полный switch по запечатанному типу

Проверка полноты на этапе компиляции

«Полный switch по запечатанному типу» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Исчерпывающий оператор выбора

Когда оператор switch применяется к запечатанному типу, компилятор знает каждый разрешённый подтип. Если оператор выбора охватывает их все, он является полным, и ветка по умолчанию не требуется.

Оператор выбора с шаблоном типа

Выражения выбора могут сопоставлять значение с его типом во время выполнения, используя шаблоны типов.

public class Main {
    sealed interface Shape permits Circle, Square {}
    record Circle(double radius) implements Shape {}
    record Square(double side) implements Shape {}

    static String describe(Shape s) {
        return switch (s) {
            case Circle c -> "circle r=" + c.radius();
            case Square sq -> "square s=" + sq.side();
        };
    }

    public static void main(String[] args) {
        System.out.println(describe(new Circle(2)));
        System.out.println(describe(new Square(3)));
    }
}

Ветка по умолчанию не требуется

Поскольку Circle и Square — единственные разрешённые подтипы, компилятор принимает оператор выбора как полный. Добавление ветки default было бы избыточным.

Полнота во время компиляции

Если позже добавить новый разрешённый подтип и забыть обработать его, каждый полный оператор выбора не скомпилируется. Это превращает целый класс ошибок во время выполнения в ошибки компиляции.

Вычисление результата

Полные выражения выбора отлично подходят для сведения значения к результату, например к значению area.

public class Main {
    sealed interface Shape permits Circle, Square {}
    record Circle(double radius) implements Shape {}
    record Square(double side) implements Shape {}

    static double area(Shape s) {
        return switch (s) {
            case Circle c -> Math.PI * c.radius() * c.radius();
            case Square sq -> sq.side() * sq.side();
        };
    }

    public static void main(String[] args) {
        System.out.printf("%.2f%n", area(new Circle(1)));
        System.out.printf("%.2f%n", area(new Square(2)));
    }
}

Операторы выбора и выражения

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

Обработка отсутствующего значения

По умолчанию оператор выбора для ссылки выбрасывает NullPointerException, если значение отсутствует. Чтобы обработать такую ситуацию явно, можно добавить метку case null.

public class Main {
    sealed interface Shape permits Circle, Square {}
    record Circle(double radius) implements Shape {}
    record Square(double side) implements Shape {}

    static String describe(Shape s) {
        return switch (s) {
            case null -> "no shape";
            case Circle c -> "circle";
            case Square sq -> "square";
        };
    }

    public static void main(String[] args) {
        System.out.println(describe(null));
        System.out.println(describe(new Circle(1)));
    }
}

Защитные условия не нарушают полноту

Можно добавлять защитные условия с помощью when, чтобы уточнять варианты, но одного варианта с условием недостаточно для покрытия типа. Чтобы оператор оставался полным, для каждого подтипа всё равно нужен вариант без условия.

public class Main {
    sealed interface Shape permits Circle, Square {}
    record Circle(double radius) implements Shape {}
    record Square(double side) implements Shape {}

    static String size(Shape s) {
        return switch (s) {
            case Circle c when c.radius() > 10 -> "big circle";
            case Circle c -> "small circle";
            case Square sq -> "square";
        };
    }

    public static void main(String[] args) {
        System.out.println(size(new Circle(20)));
        System.out.println(size(new Circle(2)));
    }
}

Оператор выбора для запечатанного класса

Та же полнота действует и для запечатанных классов, а не только для интерфейсов.

public class Main {
    sealed static abstract class Token permits Word, Number {}
    static final class Word extends Token { final String text; Word(String t){text=t;} }
    static final class Number extends Token { final int value; Number(int v){value=v;} }

    static String show(Token t) {
        return switch (t) {
            case Word w -> "word:" + w.text;
            case Number n -> "num:" + n.value;
        };
    }

    public static void main(String[] args) {
        System.out.println(show(new Word("hi")));
        System.out.println(show(new Number(7)));
    }
}

Почему это важно

Полный оператор выбора в сочетании с запечатанными типами обеспечивает безопасный и развиваемый код. Набор вариантов описан в одном месте, а компилятор гарантирует, что при расширении модели ни один вариант не будет пропущен.

Полный пример

Здесь запечатанный тип результата преобразуется в сообщение с обработкой всех вариантов.

public class Main {
    sealed interface Result permits Ok, Err {}
    record Ok(int value) implements Result {}
    record Err(String message) implements Result {}

    static String render(Result r) {
        return switch (r) {
            case Ok ok -> "value = " + ok.value();
            case Err err -> "error: " + err.message();
        };
    }

    public static void main(String[] args) {
        System.out.println(render(new Ok(10)));
        System.out.println(render(new Err("bad input")));
    }
}

Быстрая проверка

Проверьте своё понимание полного оператора выбора.

Итоги

Вы изучили полный оператор выбора для запечатанных типов.

  • Охват всех разрешённых подтипов делает оператор выбора полным, поэтому default не требуется.
  • Пропуск нового подтипа превращается в ошибку компиляции.
  • case null позволяет явно обработать отсутствующие значения.
  • Защитные условия уточняют варианты, но не заменяют вариант без условия.

Часто задаваемые вопросы

Урок «Полный switch по запечатанному типу» бесплатный?

Да — полный текст урока «Полный switch по запечатанному типу» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «Полный switch по запечатанному типу»?

Проверка полноты на этапе компиляции Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Полный switch по запечатанному типу»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Объявление запечатанных типов
  2. Условие permits
  3. Запечатанные типы с record
  4. Полный switch по запечатанному типу
← Назад к Java Academy