Операторы switch в Java помогают обеспечить несколько возможных путей выполнения программы. Операторы switch в Java можно использовать вместо операторов if-else для написания более чистого и лаконичного кода.
Операторы switch в Java со временем эволюционировали. В этом руководстве мы узнаем об основных функциях оператора switch и новых функциях в более поздних версиях Java.
1. Операторы переключения
1.1 Синтаксис
Общая форма оператора switch —
switch(expression){case labelOne:statements;break;case labelTwo:statements;break;case labelThree:statements;break;default:statements;}
Значение выражения должно быть одним из следующих 6 типов:
- Примитивные типы данных, например byte, short, char и int
- Классы-оболочки, например, Character, Byte, Short и Integer
- Типы перечислений(добавлены в Java 5)
- Класс String(добавлен в Java 7)
Здесь labelOne, labelTwo и labelThree являются «константными выражениями времени компиляции» или константами(значение меток должно быть известно во время компиляции).
Аналогичную функциональность можно получить с помощью цепочки блоков if-else, но оператор switch более читабельный и понятный.
1.2.Поток выполнения
Оператор switch оценивается следующим образом:
- Прежде всего, оценивается выражение switch.
- Тип данных значения выражения и метки регистра должны быть одинаковыми.
- Во-вторых, значение выражения сопоставляется со значением каждой метки case. Если значение выражения соответствует метке case, выполнение начинается с соответствующей метки case и выполняет все операторы, пока не встретится оператор break.
- Если значение выражения не соответствует ни одной метке case, выполнение начинается с оператора, следующего за необязательной меткой default, и продолжается до тех пор, пока не будет встречен конец оператора switch или оператор break.
Мы можем легко догадаться, что использование оператора break внутри метки по умолчанию не является необходимым, поскольку метка по умолчанию является последней меткой в операторе switch, и выполнение оператора switch в любом случае прекратится после этого.
1.3.Демо
В этом примере мы проверяем, является ли сегодня выходным или будним днем, используя оператор switch. Для хранения всех дней недели мы создали перечисление.
Обратите внимание, что мы создали в общей сложности восемь меток случая, которые возвращают соответствующее значение «истина» или «ложь».
публичный класс SwitchStatement{public static void main(String[] args){System.out.println("Понедельник: " + isWeekDay(Day.TUE));System.out.println("Понедельник: " + isWeekDay(Day.SUN));}публичный статический логический isWeekDay(День день){Логический результат = false;переключатель(день) {случай ПН:результат = истина;перерыв;случай ТИ:результат = истина;перерыв;случай СР:результат = истина;перерыв;случай ЧТ:результат = истина;перерыв;случай ПТ:результат = истина;перерыв;случай СБ:результат = ложь;перерыв;случай ВС:результат = ложь;перерыв;по умолчанию:throw new IllegalArgumentException("Недопустимый день: " + day.name())}вернуть результат;}}перечисление День {ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС}
Приведенный выше пример работает так, как и ожидалось, но мы можем сделать его лучше. Как мы видим, несколько меток case возвращают одно и то же значение, поэтому мы можем сгруппировать метки case, чтобы сделать код более читаемым.
публичный статический логический isWeekDay(День день){Логический результат = false;переключатель(день) {случай ПН, ВТ, СР, ЧТ, ПТ:результат = истина;перерыв;случай СБ, ВС:результат = ложь;перерыв;по умолчанию:throw new IllegalArgumentException("Недопустимый день: " + day.name())}вернуть результат;}
Шанс на улучшение все еще есть. В приведенном выше примере наличие операторов break выглядит не очень хорошо. Мы можем удалить операторы break, используя новый синтаксис стрелок. Он доступен с Java 13.
публичный статический логический isWeekDay(День день){Логический результат = false;переключатель(день) {случай ПН, ВТ, СР, ЧТ, ПТ -> результат = истина;случай СБ, ВС -> результат = ложь;по умолчанию -> throw new IllegalArgumentException("Недопустимый день: " + day.name());}вернуть результат;}
2. Переключение выражений
Java 12 представила выражения switch, которые могут вычислять значение для всего оператора switch и присваивать его значение переменной. Это очень похоже на другие обычные операторы Java.
2.1. Возвращаемое значение с синтаксисом стрелок
Давайте перепишем последний пример с выражением switch. Обратите внимание на строку № 11, где мы напрямую присваиваем значение оператора switch переменной result.
публичный класс SwitchStatement{public static void main(String[] args){System.out.println("Понедельник: " + isWeekDay(Day.TUE));System.out.println("Понедельник: " + isWeekDay(Day.SUN));}публичный статический логический isWeekDay(День день){Логический результат = switch(day) {случай ПН, ВТ, СР, ЧТ, ПТ -> правда;случай СБ, ВС -> ложь;по умолчанию -> throw new IllegalArgumentException("Недопустимый день: " + day.name());};вернуть результат;}}перечисление День {ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС}
2.2 Возвращаемое значение с ключевым словом yield
В приведенном выше примере мы пишем только возвращаемое значение в операторах case. Что, если нам нужно выполнить несколько операторов, прежде чем возвращать какое-либо значение из данного блока case.
В таких случаях ключевое слово yield помогает вернуть вычисленное значение из многооператорного блока.
В данном примере мы написали только оператор печати. Вы можете написать столько операторов, сколько необходимо.
публичный статический логический isWeekDay(День день){Логический результат = switch(day) {случай ПН, ВТ, СР, ЧТ, ПТ -> {System.out.println("Сегодня будний день");выход истинный;}случай СБ, ВС -> {System.out.println("Сегодня выходные");выход ложный;}по умолчанию -> throw new IllegalArgumentException("Недопустимый день: " + day.name());};вернуть результат;}
3. Примеры переключения
3.1. Лучшая проверка instanceof с помощью операторов Switch
Традиционно, если нам приходилось писать код, проверяющий тип экземпляра и выполняющий некоторую логику, это было так:
Объект о;если(экземпляр строки){Строка s =(Строка) o;String.format("Строка %s", s)}иначе если(экземпляр целого числа){Целое число i =(Целое число) o;Строка.формат("int %d", i)}иначе если(экземпляр Double){Двойной d =(Двойной) o;String.format("double %f", d)}
В Java 17 мы можем переписать все выражение следующим образом:
Объект о;переключатель(о){case Integer i -> String.format("int %d", i);case Double d -> String.format("double %f", d);case String s -> String.format("Строка %s", s);по умолчанию -> o.toString();}
3.2 Обработка нулевых значений
Традиционные операторы switch выдают исключение NullPointerException, если выражение селектора принимает значение null.
Начиная с Java 17 мы можем проверять наличие нулевых значений как отдельный случай.
если(с == ноль) {System.out.println("ой!");возвращаться;}переключатель(и) {case "Foo", "Bar" -> System.out.println("Отлично");по умолчанию -> System.out.println("Ok");}
переключатель(и) {случай null -> System.out.println("Упс");case "Foo", "Bar" -> System.out.println("Отлично");по умолчанию -> System.out.println("Ok");}
4. Ограничения
4.1. Значения меток регистра должны находиться в диапазоне DataType
Обратите внимание, что значение константных выражений, используемых в качестве меток case, должно находиться в диапазоне типа данных выражения switch.
Диапазон типа данных byte в Java составляет от -128 до 127, поэтому следующий код не будет скомпилирован, поскольку вторая метка case равна 150, что выходит за пределы диапазона типа данных byte:
byte b = 10;switch(b) {case 5:b++;break;case 150: // A compile-time error. 150 is greater than 127b--;break;default:b = 0;}
4.2. Дублирование этикеток на корпусах не допускается.
Еще один важный момент, который следует отметить, заключается в том, что две метки case в операторе switch не могут быть одинаковыми. Следующий фрагмент кода не будет скомпилирован, поскольку метка case 10 повторяется:
int num = 10;switch(num) {case 10:num++;break;case 10: // A compile-time error. Duplicate case label 10num--;break;default:num = 100;}