Как работает switch case
Перейти к содержимому

Как работает switch case

  • автор:

Оператор switch в Java

Тип ВыражениеДляВыбора для оператора выбора switch в Java должен быть одним из следующих:

  • byte , short , char , int .
  • Их обёртки Byte , Short , Character , Integer .
  • String (начиная с Java 7).
  • Перечисление ( Enum ).

Перейдем к практике использования оператора switch в Java

Излишняя оптимизация break

Отличия от if

Switch в Java 7

Switch в Java 12

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

Ранее справа от break у нас уже ничего не могло стоять, а сейчас мы его используем как оператор return для возвращения значения нашим switch. Метки с двоеточием отмечают точку входа в блок операторов. То есть с того места начинается выполнение всего кода ниже, даже тогда, когда встречается другая метка.

Как итог — сквозной переход от метки к метке, который еще называют проваливанием (fall-through).

Switch в Java 13

В Java 13 изменился способ возврата значения из switch. Если в java 12 возвращаемое значение мы писали после break, который служил у нас как return для блока switch, то сейчас возвращать значение мы будем с помощью слова yield . Смотрим: В тоже время, код, написанный на java 12 c использованием break для возврата, компилироваться не будет(( Оператор switch в Java - 3Break будет использоваться, но в тех ситуациях, когда нам не нужно ничего возвращать. Оператор switch в Java - 4

Полное руководство по switch в Java

Старый добрый switch был в Java с первого дня. Мы все используем его и привыкли к нему — особенно к его причудам (кого-нибудь еще раздражает break?). Но начиная с Java 12, ситуация начала меняться: switch вместо оператора стал выражением:

Результат работы switch-выражения теперь можно сохранять в переменную; ушла необходимость использовать break в каждой ветке case благодаря лямбда-синтаксису и многое другое.

Когда дело доходит до switch после Java 14, необходимо выбрать стиль его использования:

  • оператор или выражение (с Java 14)
  • двоеточия или стрелки (с Java 14)
  • метки или шаблоны (3-й превью в Java 19)
    В этом руководстве я расскажу обо всем, что необходимо знать о switch-выражениях, и как их лучше всего использовать в современной Java.

Недостатки оператора switch

Прежде, чем мы перейдем к обзору нововведений, давайте рассмотрим один пример кода. Допустим, мы столкнулись с «ужасным» тернарным boolean и хотим преобразовать его в обычный boolean. Вот один из способов сделать это:

Реализация данного кода хромает: наличие break в каждой ветке, которые легко забыть; можно не учесть все возможные значения ternaryBool (забыть реализовать какой-то case); с переменной result не все гладко — область видимости не соответствует ее использованию; нельзя объявить в разных ветках переменные с одинаковым именем. Согласитесь, что данное решение выглядит крайне громоздко и неудобно — тут явно есть, что улучшить.

А вот пример попроще, демонстрирующий похожие проблемы:

Давайте попробуем устранить все недостатки, поместив switch в отдельный метод:

Так намного лучше: отсутствует фиктивная переменная result, нет break, загромождающих код и сообщений компилятора об отсутствии default (даже если в этом нет необходимости, как в данном случае).

Но если подумать, то мы не обязаны создавать методы только для того, чтобы обойти неуклюжую особенность языка. И это даже без учёта, что такой рефакторинг не всегда возможен. Нет, нам нужно решение получше!

Представляем switch-выражения!

Начиная с Java 12 и выше, вы можете решить вышеуказанные проблемы следующим образом:

Я думаю, что это довольно очевидно: если ternartBool равен TRUE, то result будет присвоено true, а FALSE становится false.

Сразу возникают две мысли:

  • switch теперь может иметь результат
  • какие возможности предоставляют стрелки?

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

Выражение vs оператора

Возможно, вы удивлены, что switch теперь является выражением. А чем же он был до этого? До Java 12 switch был оператором — императивной конструкцией, управляющей исполняющим потоком.

Думайте о различиях старой и новой версии switch, как о разнице между if и тернарным оператором. Они оба проверяют логическое условие и выполняют ту или иную ветку в зависимости от его результата.

Разница состоит в том, что if просто выполняет соответствующий блок, тогда как тернарный оператор возвращает какой-то результат:

То же самое и у switch: до Java 12, если вы хотели вычислить значение и сохранить результат, то должны были либо присвоить его переменной, либо вернуть из метода, созданного специально для оператора switch.

Теперь же результат вычислений оператора switch может быть присвоен переменной.

Еще одно отличие заключается в том, что поскольку выражение является частью оператора, то оно должно заканчиваться точкой с запятой, в отличие от классического оператора switch.

Стрелка vs двоеточия

В самом начале статьи использовался пример с новым синтаксисом в лямбда-стиле со стрелкой между меткой и выполняющейся частью. Эквивалентный ему код без лямбда-стиля можно записать так:

Обратите внимание, что вам нужно использовать новое ключевое слово yield, чтобы вернуть значение из ветки case (этот синтаксис появился в Java 13. В Java 12 вместо yield применялся break, т. е. break true вместо yield true, что выглядело странно).

Исторически сложилось, что метки с двоеточием определяют точку входа в блок операторов. С этого места начинается выполнение всего кода ниже, даже когда встречается другая метка (при отсутствии break). Механизм такой работы известен, как сквозной переход к следующему case. Для его прерывания нужен break или return.

Использование же стрелки позволяет выполнять только блок справа от нее. И никакого «проваливания».

Подробнее об эволюции switch

Несколько меток на case

Отсутствие break в case часто используется для применения одинакового поведение к веткам с разными метками. При этом программа будет переходить к следующему case, пока не наткнется на break. Из этого можно сделать вывод, что оператор switch в каждом case поддерживает наличие только одной метки:

А в новом switch один case может соответствовать нескольким меткам:

Поведение этого кода очевидно: TRUE и FALSE приводят к одному и тому же результату — вычисляется выражение «sane».

Подробнее о стрелке

Начиная с Java 14, switch позволяет использовать лямбда-стрелку для «сопоставления» case с кодом:

Давайте рассмотрим два свойства, характерных для стрелочной формы записи разделителя:

  • отсутствие сквозного перехода к следующему case
  • блоки операторов

Отсутствие сквозного перехода к следующему case

Вот, что говорится в JEP 325 об этом:

Я полностью согласен и приветствую возможность использовать switch без поведения по умолчанию:

Стрелка позволяет вывести «Bool was sane» в единственном экземпляре, в то время, как с двоеточием это же сообщение отобразилось бы дважды.

Блоки операторов

Как и в случае с лямбдами, стрелка может указывать либо на один оператор (как выше), либо на блок, выделенный фигурными скобками:

Блоки необходимы для использования более одной строки кода в case. При этом они имеют дополнительное преимущество — позволяют создавать одинаковые имена переменных в разных ветках за счет локальной области видимости для каждой ветки.

Если вам показался необычным способ выхода из блоков с помощью yield, а не return, то это необходимо, чтобы избежать путаницы: return может быть неправильно истолкован, как выход из метода. Мы лишь завершаем работу switch, оставаясь в том же методе.

Подробнее о выражениях switch

И последнее, но не менее важное — особенности использования switch в качестве выражения:

  • множественные выражения
  • ранний возврат
  • охват всех значений (исчерпываемость)

Множественные выражения

Switch-выражения являются множественными выражениями. Это означает, что они не имеют своего собственного типа, но могут быть одним из нескольких типов. Наиболее часто в качестве таких выражений используются лямбда-выражения: s -> s + » «, могут быть и Function<String, String>, и Function<Serializable, и Object> или UnaryOperator.

Тип switch-выражения определяется исходя из типов его веток, а также из места его использования. Если результат работы switch-выражения присваивается типизированной переменной, передается в качестве аргумента или используется в контексте, где известен точный тип (целевой тип), то все его ветки должны соответствовать этому типу. Вот, что мы делали до сих пор:

Как итог — switch присваивается переменной String result. Следовательно, String является целевым типом, и все ветки должны возвращать результат этого типа.

То же самое происходит и здесь:

А что произойдет сейчас?

Про применение типа var можно прочитать в статье: «26 рекомендаций по использованию типа var в Java».

Если целевой тип неизвестен из-за использования var, то он вычисляется путем нахождения наиболее конкретного супертипа из типов, создаваемых ветками.

Ранний возврат

Следствием различия между выражением и оператором switch является то, что вы можете использовать return для выхода из оператора switch:

А вот внутри выражения использовать return уже не получится:

Это имеет смысл независимо от того, используете ли вы стрелку или двоеточие.

Охват всех значений (исчерпываемость)

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

Switch-выражения усугубляют эту проблему. Куда следует перейти switch, если нужная метка отсутствует? Единственный ответ, который может дать Java — это возвращать null для ссылочных типов и значение по умолчанию для примитивов. Это породило бы множество ошибок в основном коде.

Чтобы предотвратить такой исход, компилятор может помочь вам. Для switch-выражений компилятор будет настаивать, чтобы все возможные варианты были охвачены. Для каждого возможного значения переменной switch должна быть ветвь — это называется исчерпываемостью. Давайте посмотрим на пример, который может привести к ошибке компиляции:

Интересным является следующее решение: добавление ветки default, конечно, исправит ошибку, но это не является единственным решением — еще можно добавить case для FALSE.

Да, компилятор наконец-то сможет определить, охватываются ли все значения enum, что позволяет не использовать бесполезные значения в default!

Что касается исчерпываемости, я стараюсь избегать ветвей по умолчанию, когда это возможно, предпочитая получать ошибки компиляции, когда что-то меняется.

Хотя, это все же вызывает один вопрос. Что делать, если кто-то возьмет и превратит сумасшедший Bool в кватернионный (с четырьмя значениями) Boolean, добавив четвертое значение? Если вы перекомпилируете switch-выражение для расширенного Bool, то получите ошибку компиляции (т. к. выражение больше не будет исчерпывающим). Чтобы отловить эту проблему, компилятор переходит в ветку default, которая ведет себя так же, как та, которую мы использовали до сих пор, вызывая исключение.

В настоящее время охват всех значений без ветки default работает только для enum, но когда switch в будущих версиях Java станет более мощным, он также сможет работать и с произвольными типами. Если метки case смогут не только проверять равенство, но и проводить сравнения (например _ < 5 -> …) — это позволит охватить все варианты для числовых типов.

Как пользоваться switch в современной Java

До этого мы рассматривали изменения, которые произошли до Java 14. Теперь обсудим то, что было реализовано после.

Паттерны (шаблоны)

Реализация сопоставления с образцом в switch все еще находится в процессе разработки, но есть три аспекта, которые особенно интересны по данной теме.

Паттерны типов

На момент написания статьи Java поддерживает только паттерны типов (Type Patterns) с паттернами деконструкции для записей (records), предложенными JEP 405. Их уже можно использовать в операторах if и switch:

Я думаю, что с такими возможностями switch станет более функциональным и интуитивным за счет того, что:

  • более четко выражает намерение выполнить ровно одну ветвь на основе свойств obj
  • компилятор проверяет исчерпываемость
  • если необходимо вычислить значение, то использование switch в качестве выражения является более кратким

Применение уточнений (Clauses)

Уточнения (ранее — guarded patterns) расширяют возможности паттерна с помощью дополнительных логических проверок. Это может быть представлено следующим образом (синтаксис, придуманный мной):

По мере того, как switch становится все более мощным, я предполагаю, что он начнет поглощать части кода, для реализации которых используется if-else-if.

Выводы

Из статьи мы узнали, что Java превращает switch в выражение, наделяя его новыми возможностями:

Как работает switch case

Конструкция switch-case позволяет сравнить некоторое выражение с набором значений. Она имеет следующую форму:

После ключевого слова switch в скобках идет сравниваемое выражение. Значение этого выражения последовательно сравнивается со значениями после оператора сase . И если совпадение будет найдено, то будет выполняться определенный блок сase .

Стоит отметить, что сравниваемое выражение в switch должно представлять один из целочисленных или символьных типов или перечисление (рассматриваются далее).

В конце конструкции switch может стоять блок default . Он необязателен и выполняется в том случае, если значение после switch не соответствует ни одному из операторов case. Например:

Чтобы избежать выполнения последующих блоков case/default, в конце каждого блока ставится оператор break . То есть в данном случае будет выполняться оператор

После выполнения оператора break произойдет выход из конструкции switch..case, и остальные операторы case будут проигнорированы. Поэтому на консоль будет выведена следующая строка

Стоит отметить важность использования оператора break . Если мы его не укажем в блоке case , то после этого блока выполнение перейдет к следующему блоку case. Например, уберем из предыдущего примера все операторы break:

В этом случае опять же будет выполняться оператор case 2: , так как переменная x=2. Однако так как этот блок case не завершается оператором break, то после его завершения будет выполняться набор инструкций после case 3: даже несмотря на то, что переменная x по прежнему равна 2. В итоге мы получим следующий консольный вывод:

Совмещение условий

Можно определять для нескольких меток case один набор инструкций:

Здесь если x=1 или x=2 , то выполняется одна и та же инструкция std::cout << «x = 1 or 2» << «\n» . Аналогично для вариантов x=3 и x=4 также определена общая инструкция.

Переменные в блоках case

Определение переменных в блоках case , возможно, встречается нечасто. Однако может вызвать затруднения. Так, если переменная определяется в блоке case, то все инструкции блока помещаются в фигурные скобки (для блока default это не требуется):

Блок switch с инициализацией переменной

Иногда в конструкции switch для различных промежуточных вычислений необходимо определить переменную. Для этой цели начиная со стандарта C++17 язык С++ поддерживает особую форму конструкции switch :

Подобная форма также принимает выражение, значение которого сравнивается с константами после операторов case . Но теперь перед выражением еще может идти определение и инициализация переменной. Например:

В данном случае в конструкции switch определяется переменная k , которая доступна только в рамках этой конструкции switch . В качестве выражения используется значение переменной op , которая представляет знак операции. И в зависимости от этого значения, выполняем определенную операцию с переменными n и k.

What is a Switch Case In Java?

Java programming language has conditional and control statements which optimizes the logic while writing a program. Hustle free logic building using the switch case results in improved efficiency. Using a switch case in java optimizes the readability of the code while working on multiple test expressions. In this article, you will learn about switch case in java with various examples. Following are the topics discussed in this article:

  • What is a Switch Case In Java?
  • Rules To Remember
  • Flow Chart
  • Examples
  1. Break Statement In Switch Case

2. Nested Switch Case

3. Fall-Through Switch Case

4. Enum In Switch Case

5. String In Switch Case

What Is A Switch Case In Java?

Java switch statement is like a conditional statement which tests multiple values and gives one output. These multiple values that are tested are called cases. It is like a multi-branch statement. After the release of java 7 we can even use strings in the cases. Following is the syntax of using a switch case in Java.

Rules To Remember

There are a certain rules one must keep in mind while declaring a switch case in java. Following are a certain points to remember while writing a switch case in java.

  1. We cannot declare duplicate values in a switch case.
  2. The values in the case and the data type of the variable in a switch case must be same.
  3. Variables are not allowed in a case, it must be a constant or a literal.
  4. The break statement fulfills the purpose of terminating the sequence during execution.
  5. It is not necessary to include the break statement, the execution will move to the next statement if the break statement is missing.
  6. The default statement is optional as well, it can appear anywhere in the block.

Flow Chart

Examples

Break Statement In Switch Case

Break statement is used to control the flow of the execution, as soon as the expression is satisfied the execution moves out the switch case block.

Output: july

Nested Switch Case

Nested switch case incorporates another switch case in an existing switch case. Following is an example showing a nested switch case.

Output: advance java

Fall Through Switch Case

Whenever there is no break statement involved in a switch case block. All the statements are executed even if the test expression is satisfied. Following is an example of a fall through switch case.

Enum In Switch Case

Switch case allows enum as well. Enum is basically a list of named constants. Following is an example of the use of enum in a switch case.

String In Switch Case

After the release of Java 7, a switch case can have strings as a case. Following is an example of using string as cases in a switch statement.

In this article, we have discussed how we can use switch case in java with various examples. With the use of conditional statements it becomes easier to test multiple conditions at once and also generate an optimized solution of rather difficult problem. If you wish to check out more articles on the market’s most trending technologies like Artificial Intelligence, DevOps, Ethical Hacking, then you can refer to Edureka’s official site.

Do look out for other articles in this series that will explain the various other aspects of Java.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *