🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!
Немного теории о switch в Java
Представьте себе рыцаря, остановившегося на развилке дороги. Пойдёшь налево — потеряешь коня. Пойдёшь направо — получишь знания. Как это описать в коде? Вы, вероятно, уже знаете, что для этого используются конструкции типа if-then и if-then-else .
if (turn_left) {
System.out.println("You will lose your horse");
}
if (turn_right) {
System.out.println("You will gain knowledge");
}
else
System.out.println("So you're just going to stand there?");Run CodeНо что, если дорог не две, а десять? Например, есть дороги, которые находятся “полностью справа”, “немного левее этого”, “еще немного левее” и так 10 возможных направлений?
Только представьте, во что превратится код с "if-then-else"!
if (option1)
{…}
else if (option2)
{…}
…
else if (optionN) ...Run CodeПредположим, есть развилка на 10 дорог (важно: количество вариантов должно быть конечным). Для таких ситуаций в Java есть оператор switch.
switch (ExpressionForMakingAChoice) {
case (Value1):
Code1;
break;
case (Value2):
Code2;
break;
...
case (ValueN):
CodeN;
break;
default:
CodeForDefaultChoice;
break;
}Run CodeВот как это работает:
- Вычисляется выражение
ForMakingAChoice. Затем операторswitchсравнивает полученное значение сValueX(в том порядке, в котором они перечислены). - Если
ExpressionForMakingAChoiceсовпадает сValueX, то выполняется код, следующий за двоеточием. - Если встречается оператор
break, то происходит выход изswitch. - Если
ExpressionForMakingAChoiceне соответствует ни одномуValueX, то срабатываетCodeForDefaultCase.
Важные моменты
- В операторе
switchтип выраженияExpressionForMakingAChoiceдолжен быть одним из следующих:byte,short,char,int.Byte,Short,Character,Integer.String.Enum.
- Блок
defaultявляется необязательным. Если он отсутствует и выражениеForMakingAChoiceне совпадает ни с однимValueX, то никакое действие не будет выполнено. - Оператор
breakтакже не обязателен. Если он отсутствует, код будет продолжать выполняться (игнорируя дальнейшие сравнения в операторахcase) до первого появленияbreakили до конца оператораswitch. - Если один и тот же код должен быть выполнен для нескольких вариантов, можно устранить дублирование, указав несколько идущих подряд
case.
Теперь посмотрим, как используется оператор switch в Java
Не волнуйтесь: мы закончили с теорией. После того как вы увидите следующие примеры, все станет гораздо понятнее. Рассмотрим пример из астрономии, связанный с планетами нашей Солнечной системы.
В соответствии с последними международными договоренностями, мы исключили Плутон (из-за особенностей его орбиты). Напомним, что наши планеты расположены по расстоянию от Солнца следующим образом: Меркурий, Венера, Земля, Марс, Юпитер, Сатурн, Уран и Нептун.
Давайте напишем метод, который принимает порядковый номер планеты (относительно ее расстояния от Солнца) и возвращает основные компоненты ее атмосферы в виде List<String>.
Напомним, что у некоторых планет состав атмосферы совпадает. Так, Венера и Марс содержат в основном углекислый газ, атмосфера Юпитера и Сатурна состоит из водорода и гелия, а Уран и Нептун добавляют к последней паре газов метан.
Вот наш метод:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No atmosphere");
break;
case 2:
case 4: result.add("Carbon dioxide");
break;
case 3: result.add("Carbon dioxide");
result.add("Nitrogen");
result.add ("Oxygen");
break;
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
break;
case 7:
case 8: result.add("Methane");
result.add("Hydrogen");
result.add("Helium");
break;
default:
break;
}
return result;
}Run CodeОбратите внимание, что для планет с одинаковым составом атмосферы используется один и тот же код — просто перечислены несколько case подряд.
Если мы хотим получить состав атмосферы нашей родной планеты, мы вызываем наш метод с 3 в качестве аргумента:
getPlanetAtmosphere(3).
System.out.println(getPlanetAtmosphere(3)) returns ["Carbon dioxide", "Nitrogen", "Oxygen"].Run CodeЭксперимент с break:
Что произойдет, если убрать все операторы break? Проверим:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No atmosphere");
case 2:
case 4: result.add("Carbon dioxide");
case 3: result.add("Carbon dioxide");
result.add("Nitrogen");
result.add ("Oxygen");
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
case 7:
case 8: result.add("Methane");
result.add("Hydrogen");
result.add("Helium");
default:
}
return result;
}Run CodeЕсли вывести результат System.out.println(getPlanetAtmosphere(3)), то окажется, что наша родная планета не так уж и пригодна для жизни. Или нет? Смотрите сами:
["Carbon dioxide", "Nitrogen", "Oxygen", "Hydrogen", "Helium", "Methane", "Hydrogen", "Helium"].
Почему это произошло? Потому что программа выполняет все case начиная с первого совпадения и до конца блока switch.
Чрезмерная оптимизация с использованием break
Обратите внимание, что можно улучшить этот метод, по-другому расположив операторы break и case:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No atmosphere");
break;
case 3: result.add("Nitrogen");
result.add ("Oxygen");
case 2:
case 4: result.add("Carbon dioxide");
break;
case 7:
case 8: result.add("Methane");
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
}
return result;
}Run CodeВыглядит компактнее, правда? Мы сократили количество операторов, изменив порядок case и объединив их. Теперь каждый тип газа добавляется в список всего одной строкой.
Код, приведенный в последнем примере, лишь показывает, как все работает. Мы не рекомендуем писать код таким образом. Поддержка такого кода (особенно другим разработчиком) превратится в головоломку: логику построения этих блоков будет крайне трудно восстановить.
Отличия от if
Учитывая внешнее сходство операторов if и switch, не забывайте, что оператор switch выбирает один из случаев на основе конкретного значения, тогда как if может использовать любое булево выражение. Помните об этом, когда проектируете свой код.
Ограничения для меток case: что можно и что нельзя использовать
Сначала разберемся с метками case. Возможно, вы думаете: “Могу ли я использовать здесь любое выражение?” Не совсем. В Java существуют строгие правила относительно того, что можно поместить после ключевого слова case.
Золотое правило: метки case должны быть константными выражениями. Это значит, что их значение должно быть известно компилятору уже на этапе компиляции. Никаких переменных!
Пример некорректной метки case:
int number = 2;
switch (number) {
case number: // Error! 'number' is a variable, not a constant.
System.out.println("Invalid case label.");
break;
}Run CodeПример корректной метки case:
final int CONST_NUMBER = 2; // 'final' makes this a constant.
switch (CONST_NUMBER) {
case 2:
System.out.println("This is valid!");
break;
}Run CodeОсновные выводы:
- метки
caseдолжны быть константными выражениями (например,final-переменные, литералы или константыenum); - нельзя использовать переменные или выражения, которые могут изменяться во время выполнения.
Визуализация switch-case с помощью блок-схемы
Иногда картинка действительно стоит тысячи слов. Давайте посмотрим, как работает оператор switch-case, используя блок-схему. Это поможет понять, как именно проходит поток управления между разными ветками.
Разбираем блок-схему
Теперь давайте разберемся в этой схеме. Вот как она работает шаг за шагом:
- Start: программа начинает выполняться.
- Evaluate Expression: значение в операторе
switchвычисляется. - Compare Cases: программа последовательно проверяет каждую метку
case. - Match Found: если совпадение найдено, выполняется соответствующий блок кода.
- Break: если есть оператор
break, программа выходит изswitch. Если нет, она продолжает выполняться (это называется fall-through). - Default: если соответствие не найдено, запускается блок
default(если он задан). - End: программа продолжает работу после блока
switch.
Не так уж и страшно, если все разложить по полочкам!
Зачем использовать блок-схемы для понимания логики switch-case?
Теперь вы, возможно, спросите: “Зачем нужны блок-схемы?”. Отличный вопрос!
- Наглядность: блок-схемы дают возможность увидеть в общих чертах, как принимаются решения в вашей программе.
- Облегчение отладки: они помогают понять, где именно может быть ошибка в логике, особенно в сложных условиях.
- Ускоренное обучение: для тех, кто лучше воспринимает информацию визуально, схема ускоряет понимание.
- Удобная документация: блок-схемы помогают объяснить код коллегам или будущим пользователям.
Пример работы switch-case
Рассмотрим теперь это все на практике!
Пример: выбор уровня игры
import java.util.Scanner;
public class GameLevel {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Select your level: 1 (Easy), 2 (Medium), 3 (Hard)");
int level = scanner.nextInt();
switch (level) {
case 1:
System.out.println("You've chosen Easy mode. Good luck!");
break;
case 2:
System.out.println("You've chosen Medium mode. Let's go!");
break;
case 3:
System.out.println("You've chosen Hard mode. Brace yourself!");
break;
default:
System.out.println("Invalid choice. Please select 1, 2, or 3.");
}
}
}Run CodeВ этом примере программа проверяет ввод пользователя и выполняет соответствующий блок кода. Оператор break гарантирует, что выполнится только один блок, предотвращая падение к следующему случаю!
Заключение
- Используйте оператор
switch-case, если необходимо обработать более двух ветвей, чтобы не перегружать код многочисленнымиif. - Не забудьте завершить логический блок для каждого конкретного значения (оператор case), вставив оператор
break. - В выражении
switchможно использовать не только примитивные типы, но иEnum, а такжеString. - Помните про блок
default— он нужен для обработки непредвиденных значений. - Для оптимизации производительности поместите наиболее часто используемые ветви в начало блока
switch. - Не увлекайтесь “оптимизацией”, удаляя
break— такой код становится трудночитаемым и сложным для поддержки.
Перевод статьи «Java Switch Statement».
