Для чего используется конструкция switch
Полное руководство по switch-выражениям в Java 12
В этом руководстве я расскажу Вам обо всем, что необходимо знать о switch-выражениях в Java 12.
Предварительный обзор
Это означает, что данная управляющая конструкция может быть изменена в будущих версиях спецификации языка.
Так что имейте ввиду, что switch, как выражение, не имеет на данный момент окончательного варианта синтаксиса в Java 12.
Если у вас возникло желание поиграть со всем этим самим, то вы можете посетить мой демо-проект Java X на гитхабе.
Проблема с операторами в switch
Прежде, чем мы перейдем к обзору нововведений в switch, давайте быстро оценим одну ситуацию. Допустим, мы столкнулись с «ужасным» тернарным булеаном и хотим преобразовать его в обычный булеан. Вот один из способов сделать это:
Согласитесь, что это очень неудобно. Как и многие другие варианты switch, встречающиеся в «природе», представленный выше пример просто вычисляет значение переменной и присваивает его, но реализация обходная (объявляем идентификатор result и используем его позже), повторяющаяся (мои break ‘и всегда результат copy-pasta) и подвержена ошибкам (забыл еще одну ветку? Ой!). Тут явно есть, что улучшить.
Давайте попробуем решить эти проблемы, поместив switch в отдельный метод:
Так намного лучше: отсутствует фиктивная переменная, нет break ‘ов, загромождающих код и сообщений компилятора об отсутствии default (даже если в этом нет необходимости, как в данном случае).
Но, если подумать, то мы не обязаны создавать методы только для того, чтобы обойти неуклюжую особенность языка. И это даже без учёта, что такой рефакторинг не всегда возможен. Нет, нам нужно решение получше!
Представляем switch-выражения!
Как я показал в начале статьи, начиная с Java 12 и выше, вы можете решить вышеуказанную проблему следующим образом:
Сразу возникают две мысли:
Прежде чем углубляться в детали новых возможностей switch, в начале я расскажу об этих двух основных аспектах.
Выражение или оператор
Возможно, вы удивлены, что switch теперь является выражением. А чем же он был до этого?
До Java 12 switch был оператором — императивной конструкцией, регулирующей поток управления.
Думайте о различиях старой и новой версии switch, как о разнице между if и тернарным оператором. Они оба проверяют логическое условие и выполняют ветвление в зависимости от его результата.
Разница в том, что if просто выполняет соответствующий блок, тогда как тернарный оператор возвращает какой-то результат:
Теперь же всё выражение оператора switch оценивается (выбирается для выполнения соответствующая ветка), и результат вычислений может быть присвоен переменной.
Еще одним отличием между выражением и оператором является то, что выражение switch, поскольку оно является частью оператора, должно заканчиваться точкой с запятой, в отличие от классического оператора switch.
Стрелка или двоеточие
В вводном примере использовался новый синтаксис в лямбда-стиле со стрелкой между меткой и выполняющейся частью. Важно понимать, что для этого не обязательно использовать switch в качестве выражения. Фактически, пример ниже эквивалентен приведенному в начале статьи коду:
Обратите внимание, что теперь вы можете использовать break со значением! Это идеально согласуется с инструкциями switch старого стиля, которые используют break без какого-либо значения. Так в каком случае стрелка означает выражение вместо оператора, для чего она здесь? Просто хипстерский синтаксис?
В свою очередь, использование стрелки означает, что будет выполнен только блок справа от нее. И никакого «проваливания».
Подробнее об эволюции switch
Несколько меток на case
До сих пор каждый case содержал только одну метку. Но теперь все изменилось — один case может соответствовать нескольким меткам:
Поведение должно быть очевидным: TRUE и FALSE приводят к одному и тому же результату — вычисляется выражение «sane».
Типы за пределами Enum
Подробнее о стрелке
Давайте рассмотрим два свойства, характерных для стрелочной формы записи разделителя:
Отсутствие сквозного перехода к следующему case
Вот, что говорится в JEP 325 об этом:
Текущий дизайн оператора switch в Java тесно связан с такими языками, как C и C++ и по умолчанию поддерживает сквозную семантику. Хотя этот традиционный способ управления часто полезен для написания низкоуровневого кода (такого как парсеры для двоичного кодирования), поскольку switch используется в коде более высокого уровня, ошибки такого подхода начинают перевешивать его гибкость.
Я полностью согласен и приветствую возможность использовать switch без поведения по умолчанию:
Важно усвоить, что это не имеет никакого отношения к тому, используете ли вы switch в качестве выражения или оператора. Решающим фактором тут является стрелка против двоеточия.
Блоки операторов
Как и в случае с лямбдами, стрелка может указывать либо на один оператор (как выше), либо на блок, выделенный фигурными скобками:
Блоки, которые приходится создавать для многострочных операторов имеют дополнительное преимущество (что не требуется при применении двоеточия), которое заключается в том, что для использования одинаковых имен переменных в разных ветках, switch не требует специальной обработки.
Подробнее о выражениях switch
И последнее, но не менее важное — особенности использования switch в качестве выражения:
Обратите внимание, что при этом не имеет значения, какая форма используется!
Множественные выражения
С помощью switch-выражений тип определяется по взаимодействию между тем, где используется switch и типами его веток. Если switch-выражение назначается типизированной переменной, передается в качестве аргумента или иным образом используется в контексте, где известен точный тип (это называется целевым типом), то все его ветки должны соответствовать этому типу. Вот что мы делали до сих пор:
То же самое происходит и здесь:
А что произойдет сейчас?
(Про использование типа var читайте в нашей прошлой статье 26 рекомендаций по использованию типа var в Java — примечание переводчика)
Если целевой тип неизвестен, из-за того, что мы используем var, тип вычисляется путем нахождения наиболее конкретного супертипа из типов, создаваемых ветками.
Ранний возврат
Следствием различия между выражением и оператором switch является то, что вы можете использовать return для выхода из оператора switch :
… вы не можете использовать return внутри выражения …
Это имеет смысл независимо от того, используете ли вы стрелку или двоеточие.
Покрытие всех вариантов
Чтобы предотвратить такой исход, компилятор может помочь вам. Для switch-выражений компилятор будет настаивать, чтобы все возможные варианты были охвачены. Давайте посмотрим на пример, который может привести к ошибке компиляции:
Да, компилятор наконец-то сможет определить, охватываются ли все значения enum (исчерпывают ли все варианты), и не установить бесполезные значения по умолчанию! Давайте посидим минуту в безмолвной благодарности.
Размышление
Из статьи мы узнали, что Java 12 превращает switch в выражение, наделяя его новыми возможностями:
Затем, предполагая, что switch остается таким, каким он является в данный момент, я думаю, что стрелочная форма станет новым вариантом по умолчанию. Без сквозного перехода к следующему case и с лаконичными лямбда-выражениями (это очень естественно иметь case и один оператор в одной строке) switch выглядит намного компактнее и не ухудшает читаемость кода. Я уверен, что буду использовать только двоеточие, если у меня возникнет необходимость в сквозном проходе.
Что вы думаете? Довольны тем, как все сложилось?
Подробно про оператор switch в Java
В этом руководстве вы научитесь использовать оператор switch в Java для управления потоком выполнения вашей программы.
В Java мы использовали if..else..if для выполнения блока кода среди нескольких блоков. Однако синтаксис if … else … if слишком длинный.
Следовательно, мы можем использовать оператор switch вместо длинных if … else … if. Использование операторов switch делает наш код более читабельным.
Switch эволюционировал со временем – были добавлены новые поддерживаемые типы, особенно в Java 5 и 7. Кроме того, он продолжает развиваться – выражения switch, вероятно, будут введены в Java 12.
Синтаксис оператора switch
Оператор switch оценивает выражение (в основном переменное) и сравнивает его со значениями (могут быть выражениями) каждой метки case.
Теперь, если значение соответствует определенной метке case, то выполняются все операторы соответствующей метки case.
Например, если переменная / выражение равно значению 2. В этом случае выполняются все операторы этого совпадающего case (операторы case2).
Обратите внимание, что в каждом случае используются операторы break. Оператор break используется для завершения выполнения оператора switch.
Это важно, потому что если break не используется, все операторы после соответствующего case выполняются последовательно до конца оператора switch.
Что следует помнить:
Пример 1
The day is Wednesday
В приведенном выше примере мы использовали оператор switch, чтобы узнать день недели. Здесь у нас есть переменная неделя, которая содержит целочисленное значение. Значение сравнивается с каждым случаем внутри блока переключателя.
Здесь значение недели равно 4. Следовательно, оно соответствует случаю 4. Таким образом, выполняется оператор внутри случая 4.
Пример 2: создание калькулятора с использованием оператора switch
Программа ниже принимает от пользователя три ввода: один оператор и 2 числа. На основе оператора, предоставленного пользователем, он выполняет расчет чисел. Затем результат отображается на экране.
Перед тем как приступить к работе с программой, убедитесь, что вы знаете о Java Scanner, чтобы принимать данные от пользователя.
В приведенном выше примере мы использовали оператор switch для создания калькулятора на Java. Он выполняет расчет на основе оператора, предоставленного пользователем.
Пример 3
Допустим, у нас есть следующие вложенные операторы if-else:
Приведенный выше код выглядит не очень хорошо, и его будет сложно поддерживать и обдумывать. Чтобы улучшить читаемость, мы могли бы использовать здесь оператор switch:
Как показано выше, мы сравниваем animal аргумента switch с несколькими значениями case. Если ни одно из значений case не равно аргументу, то выполняется блок под меткой по умолчанию.
Проще говоря, оператор break используется для выхода из оператора switch.
Заявление break
Хотя большинство операторов switch в реальной жизни подразумевают, что должен быть выполнен только один из блоков case, оператор break необходим для выхода из switch после завершения блока.
Чтобы продемонстрировать это, опустим операторы break и добавим вывод в консоль для каждого блока:
Давайте выполним этот код ForgotBreakInSwitch(«DOG») и проверим вывод, чтобы убедиться, что все блоки выполняются:
domestic animal
unknown animal
Поэтому нам следует быть осторожными и добавлять операторы break в конце каждого блока, если нет необходимости переходить к коду под следующей меткой.
Единственный блок, в котором не требуется разрыв, – это последний, но добавление разрыва к последнему блоку делает код менее подверженным ошибкам.
Мы также можем воспользоваться этим поведением, чтобы опустить break, когда мы хотим, чтобы один и тот же код выполнялся для нескольких операторов case. Давайте перепишем пример из предыдущего раздела, сгруппировав первые 2 случая:
Переключение Аргумента и регистра значений
Теперь давайте обсудим допустимые типы аргументов switch и значений case, требования к ним и то, как оператор switch работает со строками.
Типы данных
Мы не можем сравнивать все типы объектов и примитивов в операторе switch. Переключатель работает только с четырьмя примитивами и их оболочками, а также с типом перечисления и классом String:
Тип String доступен в операторе switch, начиная с Java 7. Тип перечисления был представлен в Java 5 и с тех пор доступен в операторе switch. Классы-оболочки также доступны с Java 5.
Конечно, аргументы переключателя и значения case должны быть одного типа.
Нет null значений
Мы не можем передать нулевое значение в качестве аргумента инструкции switch. Если мы это сделаем, программа выдаст исключение NullPointerException, используя наш первый пример переключения:
Конечно, мы также не можем передать null как значение в метку case оператора switch. Если мы это сделаем, код не скомпилируется.
Значения регистра как константы времени компиляции
Если мы попытаемся заменить значение case DOG переменной dog, код не будет компилироваться, пока мы не отметим переменную dog как final:
Сравнение строк
Если оператор switch использовал оператор равенства для сравнения строк, мы не смогли бы правильно сравнить аргумент String, созданный с помощью оператора new, со значением case String.
К счастью, оператор switch использует скрытый метод equals().
switch выражения
JDK 13 теперь доступен и содержит улучшенную версию новой функции, впервые представленной в JDK 12: выражения switch.
Чтобы включить его, нам нужно передать компилятору параметр –enable-preview.
Новое выражение переключателя
Давайте посмотрим, как выглядит новое выражение переключения при переключении через несколько месяцев:
Отправка значения типа Month.JUNE установит результат в 3.
Ключевое слово yield
Если пойти немного дальше, то есть возможность получить детальный контроль над тем, что происходит в правой части выражения, с помощью блоков кода. В таком случае нам нужно использовать ключевое слово yield:
Возврат внутри выражения переключателя
Вследствие различия между операторами switch и выражениями переключения, можно вернуться изнутри оператора, но нам не разрешено делать это из выражения.
Следующий пример вполне допустим и будет компилироваться:
Однако следующий код не будет компилироваться, поскольку мы пытаемся выполнить возврат за пределами включающего выражения переключателя:
При использовании операторов switch на самом деле не имеет значения, охвачены ли все случаи.
Следующий код, например, имеет место быть:
Однако для выражений переключения компилятор настаивает на том, чтобы были учтены все возможные случаи. Следующий фрагмент кода, например, не будет компилироваться, так как нет случая по умолчанию и не все возможные случаи рассмотрены:
Выражение switch, однако, будет действительным, когда будут рассмотрены все возможные случаи, как в следующем примере:
Обратите внимание, что в приведенном выше фрагменте кода нет регистра по умолчанию. Пока рассмотрены все случаи, выражение switch будет действительным.
Средняя оценка / 5. Количество голосов:
Или поделись статьей
Видим, что вы не нашли ответ на свой вопрос.
Упрощайте: как использовать конструкцию switch вместо if-else в JavaScript
Условный оператор switch сравнивает выражения с доступными значениями и выполняет один или несколько блоков кода.
Синтаксис switch
Конструкция switch состоит из:
() — круглые скобки, в которых записывается выражение для оценки;
<> — фигурные скобки, внутри которых находится код выполнения.
Давайте рассмотрим пример:
Если выражение не соответствует условиям case x и case y — происходит выполнение блока default — он запускается в конце программы при наличии ошибки.
Использование break
Без break
Что будет, если мы уберем break из нашего примера?
Примеры со switch-case в JavaScript
Давайте для наглядности рассмотрим еще несколько примеров использования конструкции. Попробуйте прокомментировать их, и только потом читайте наше объяснение, договорились?
Несколько значений для одного случая
Что будет, если case записан в один ряд?
Варианты case можно располагать не в столбик, а в один ряд — выполнение кода от этого не изменится.
Вычисление дня недели
День недели — это число от 0 до 6.
В заключение
Конструкция switch-case чаще всего используется в случаях множественного выбора. Оператор switch может использоваться для обработки сразу нескольких выражений ( case ) или диапазонов.
Напомним, что конструкция switch в JavaScript имеет свои особенности:
Простой метод измерения реальной скорости загрузки страниц у посетителей сайта
Как можно закэшировать данные и выиграть в производительности
Как работает Server-Sent API с примерами
Примеры применения Javascript в Nginx’e
Как просто сделать удобный дебаг и не лазить в код или как бородатые хакеры перехватывают ajax-запросы, нарушая вашу безопасность.
В своем блоге индийский разработчик Шашват Верма (Shashwat Verma) рассказал, как преобразовать веб-сайт или веб-страницу в прогрессивное веб-приложение (PWA).
Для чего используется конструкция switch
A note on continue, continue 2, and break:
echo ‘0’;
>
// outputs a0b0c0 (and warns twice about continue in a switch statement)
echo ‘0’;
>
// outputs a0b0c0
In short, continue and break will more or less behave the same (albeit the former throws out warnings), but continue 2 will end the loop iteration, and move to the next iteration (even if there is a block in the iteration after the switch statement).
Remember, that you also could use functions in a switch.
For example, if you need to use regular expressions in a switch:
Be careful if distinguishing between NULL and (int)0. As implied in the above documentation, the case statements are equivalent to the ‘==’ operator, not the ‘===’ operator, so the following code did not work as i expected:
Alternatively, if i prefer the appearance of the switch() statement I may use a trick like the one nospam at please dot com presents:
Something fairly simple (and maybe obvious) that I didn’t see mentioned is that the default case WILL be executed even if the switched variable does not exist or is undefined.
?>
Will output: default
Just a word of warning about using switch don’t try and compare variables that contain numbers with strings like so:
Also note that you (for unknown reason for me) are allowed to use semicolons `;` along colon `:` for `case` and `default` entries:
case 1 ; // semicolon is fine
.
break;
>
This is how it works: First we have a single expression n (most often a variable), that is evaluated once. The value of the expression is then compared with the values for each case in the structure. If there is a match, the block of code associated with that case is executed. Use break to prevent the code from running into the next case automatically. The default statement is used if no match is found.
Be careful if you have mixed types of values in the switch statement. Explicitly cast your variables where possible to avoid mismatch:
I’m not sure expressions in case statements are even document (don’t see it here), but watch out for this:
«`
function switchTest($integerValue) <
switch ($integerValue) <
case ($integerValue > 10):
return ‘big’;
default:
return ‘small’;
>
>
«`
switchTest(0) will return ‘big’.
I’m really not sure why.
You can use multiple break statements within a case. In this contrived example, I get out of the first case of the switch statement once a condition is met. Just remember to include another break statement as a failsafe.
echo «It worked.» ;
break; // failsafe
default:
echo «Don’t stick cupcakes in here.» ;
break;
>
Be very careful when you’re using text strings as cases. If the variable supplied to switch() is an integer, the cases would be converted to integer before the comparison is made (usually to zero). The following snippet prints «hello».
Rewriting the function (to be three times faster) provided by [stever at ashomecare dot com 07-Sep-2007 09:11] and demonstrating points that others have made:
echo getChineseZodiac ( 2016 );
?>
You can also nest switch statements inside case statements:
As follow-up to ben dot lancaster at holler dot co dot uk’s post:
‘continue’ ends the switch, not the case, just as it would with any other flow control. Think of it as putting the execution pointer right before the ending accolade (that is, the >) because that is essentially what happens. In the case of a for loop, this would cause the iteration clause to execute, and if applicable, the loop to begin again. However, switches do not loop, which is why (as noted above, in the manual!) a continue statement essentially acts as a break when within a switch.
It’s easy to abuse the switch syntax to do some very useful things. As this example will show, the possibilities can go beyond even Duff’s Device-style craziness (not that this example is nearly as clever as Duff’s Device, but it demonstrates how you can do certain things other than simply the increment/decrement/assignment that’s possible in C).
Fundamentally, this works mostly due to the fact that, from the point of view of the assembler/interpreter, a switch block is hardly any different from a bunch of GOTO labels and if() evaluations. But, like an if() evaluation, the line of a case: statement is evaluated as an expression. So, in this case, we can perform an assignment and match the result of that assignment, because the return value of an assignment is the data that was assigned (and not the value of the variable it was assigned to, as you might expect).
The assembler/interpreter can’t use the right side of the expression as a shortcut for the result of a function, so you can’t use functions in this way in a case statement. You also can’t get around this limit on calling functions from the case line by using variable functions, because they are used in the same way as functions.
Consider the following:
» switch (c)
Операторы switch и case помогают управлять сложными условными операциями и операциями ветвления. Оператор switch передает управление в оператор внутри своего тела.
Синтаксис
selection-statement :
switch ( expression ) statement
labeled-statement :
case constant-expression : statement
default : statement
Комментарии
Значения expression и значение каждого constant-expression должны иметь целочисленный тип. Выражение constant-expression должно иметь однозначное константное целочисленное значение во время компиляции.
Оператор switch обычно используется следующим образом:
Выражения switch expression и case constant-expression должны быть целочисленного типа. Значение каждого case constant-expression в теле оператора должно быть уникальным.
В следующих примерах кода показаны операторы switch :
Специально для систем Майкрософт
В Microsoft C расширения Майкрософт по умолчанию (default) включены. Используйте параметр компилятора /Za для отключения этих расширений.