Оператор switch в Java
Оператор switch в Java: ветвление по значениям, метки case, break, default и сквозное выполнение.
Когда нужно сравнить одно значение с несколькими вариантами, длинная цепочка if/else if быстро становится громоздкой. Оператор switch — компактная альтернатива в Java: значение читается один раз, выполнение переходит к подходящему case и запускает его блок.
Базовый синтаксис
switch (value) {
case label1:
// body
break;
case label2:
// body
break;
default:
// body
break;
}Небольшой пример:
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Other");
break;
}Switch переходит к case 3:, печатает Wednesday, попадает на break и выходит.
Зачем нужен break
Без break выполнение проваливается в следующий case — даже если его метка не совпадает. Это намеренная особенность switch в стиле C, но именно она является источником бесчисленных ошибок в Java-коде:
switch (day) {
case 1:
System.out.println("Monday");
// no break!
case 2:
System.out.println("Tuesday");
break;
}Когда day == 1, выводятся и Monday, и Tuesday. Всегда добавляйте break, если вы не хотите сквозного выполнения намеренно.
Намеренное сквозное выполнение
Иногда сквозное выполнение — именно то, что нужно: группировка нескольких меток под одним блоком:
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("Weekday");
break;
case 6:
case 7:
System.out.println("Weekend");
break;
}Когда вы делаете это намеренно, добавьте комментарий // fall through, чтобы ревьюеры не подумали, что вы забыли break. (Новый синтаксис switch-выражений — рассматривается в следующей главе — полностью устраняет эту проблему.)
Какие значения принимает switch?
Традиционный switch принимает:
- Все целочисленные типы:
byte,short,int,char - Их обёртки:
Byte,Short,Integer,Character String(начиная с Java 7)- Константы
enum
Не допускаются: long, float, double, boolean и произвольные объекты. Для них используйте if/else.
String role = "admin";
switch (role) {
case "admin":
System.out.println("Full access");
break;
case "editor":
System.out.println("Write access");
break;
case "viewer":
System.out.println("Read access");
break;
default:
System.out.println("No access");
break;
}Сравнение строк в switch использует семантику String.equals — с учётом регистра. Важный нюанс: переключение по String (или любому упакованному/enum значению), равному null, выбрасывает NullPointerException. Проверяйте null перед switch или обрабатывайте его в условии:
if (role == null) {
System.out.println("No role");
} else {
switch (role) {
case "admin":
System.out.println("Full access");
break;
// ...
}
}default — ветвь по умолчанию
default выполняется, когда ни один case не совпал. Он не обязателен, но включать его — хорошая практика: это делает поведение для неожиданных значений явным.
default не обязан быть последним. По соглашению он размещается внизу, но компилятор принимает его в любом месте — при отсутствии break выполнение проваливается через него так же, как через любой другой case.
Важные правила
Несколько правил, применяемых компилятором, часто вызывают затруднения:
- Метки case должны быть константами времени компиляции. Можно использовать литералы (
case 3:), константыfinalили именаenum— но не переменные и не вызовы методов.case x:, гдеx— не-final переменная, не скомпилируется. - Метки должны быть уникальными. Два
case 3:в одном switch — ошибка компиляции. - Все case разделяют одну область видимости. Переменная, объявленная в одном case, видна в других, что может привести к конфликтам. Оборачивайте тело case в фигурные скобки
{ }, когда вам нужна локальная переменная только для этого case:
switch (day) {
case 1: {
int hours = 8;
System.out.println(hours);
break;
}
case 2:
// `hours` is not visible here
break;
}Switch с enum
enum и switch — естественная пара. Внутри switch по значению enum не нужно квалифицировать имя константы:
enum Status { PENDING, ACTIVE, DONE }
Status s = Status.ACTIVE;
switch (s) {
case PENDING: // not Status.PENDING
System.out.println("Waiting...");
break;
case ACTIVE:
System.out.println("In progress");
break;
case DONE:
System.out.println("Finished");
break;
}Практический пример
Что дальше
В Java 14 были введены switch-выражения, которые возвращают значение, устраняют сквозное выполнение и поддерживают несколько меток в одном case — современный Java-код предпочитает их всякий раз, когда целевая версия — Java 14 или выше.