Уявіть, що ви стоїте на роздоріжжі, як богатир. Ліворуч підеш – коня втратиш, праворуч підеш – знання здобудеш. Як запрограмувати таку ситуацію? Ви вже, найімовірніше, знаєте, що подібний вибір ми робимо за допомогою конструкцій if-then і if-then-else.
Для завершення такого проходу потрібно або повністю пройтися всіма елементами, або використати break чи return.
Нововведення в java 12 дає нам можливість використовувати лямбда-оператор, який, зі свого боку, гарантує, що буде виконано тільки код праворуч від нього. Без жодного "провалювання".
Який вигляд матиме попередній приклад у такому разі:
Break буде використовуватися, але в тих ситуаціях, коли нам не потрібно нічого повертати.
if (turn_left) {
System.out.println("Коня втратиш");
}
if (turn_right) {
System.out.println("Знання здобудеш");
}
else
System.out.println("Так і будеш стояти?");
А що, якщо таких доріжок не дві, а 10? Є доріжка «зовсім праворуч», «трохи лівіше», «ще трохи лівіше» і так далі, у кількості 10 штук?
Уявіть, як розростеться ваш if-then-else код у такому варіанті!
if (вариант1)
{… }
else if (варіант2)
{…}
…
else if (варіантN) ....
Отже, у вас не одна розвилка умов, а кілька, скажімо, 10 (тут важливо, що кількість розвилок обмежена). Для таких ситуацій є спеціальний оператор вибору – switch case java.
switch (ВиразДляВибору) {
case (Значення1):
Код1;
break;
case (Значення2):
Код2;
break;
...
case (ЗначенняN):
КодN;
break;
default:
КодВиборуЗаЗамовчуванням;
break;
}
Порядок виконання в операторі такий:- Обчислюється ВиразДляВибору. Далі оператор switch порівнює отриманий вираз із черговим Значенням (у порядку перерахування).
- Якщо ВиразДляВибору збігся зі Значенням, то виконується код, що йде після двокрапки.
- Якщо зустрічається конструкція break – то управління передається за межі команди switch.
- Якщо збігів ВиразДляВибору і Значень не виявлено, то управління передається КодуВиборуЗаЗамовчуванням.
Тип ВиразДляВибору для оператора вибору switch у Java має бути одним із таких:
- byte, short, char, int.
- Їхні обгортки Byte, Short, Character, Integer.
- String (починаючи з Java 7).
- Перелік (Enum).
- блок default – необов'язковий, тоді в разі відсутності збігів ВиразуДляВибору і Значень не буде виконано жодних дій.
- break не є обов'язковим, якщо його немає – код продовжить виконання (ігноруючи подальші порівняння значень у блоках case) до першого зустрінутого
break
або до кінця оператора switch. - якщо необхідно виконувати один і той самий код для кількох варіантів вибору, для виключення дублювання перед ним вказуємо кілька відповідних значень у блоках case, що йдуть підряд.
Перейдемо до практики використання оператора switch у Java
Не хвилюйтеся, з теорією покінчили, і після подальших прикладів стане все набагато зрозуміліше. Отже, приступимо. Давайте розглянемо приклад з астрономії про планети Сонячної системи. Відповідно до останніх міжнародних положень виключимо Плутон (через властивості її орбіти). Згадаймо, що планети в нас розташовані від Сонця в такій послідовності: Меркурій, Венера, Земля, Марс, Юпітер, Сатурн, Уран і Нептун. Створимо Java метод, який отримує на вхід порядковий номер планети (щодо віддаленості від Сонця), а на виході видає основний склад атмосфери цієї планети у вигляді списку List<String>. Нагадаю, у деяких планет – схожий склад атмосфери. Так, Венера і Марс містять здебільшого вуглекислий газ, у Юпітера і Сатурна він складається з водню і гелію, а Уран і Нептун на додачу до останньої пари газів також має метан. Наша функція:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("Немає атмосфери");
break;
case 2:
case 4: result.add("Вуглекислий газ");
break;
case 3: result.add("Вуглекислий газ");
result.add("Азот");
result.add("Кисень");
break;
case 5:
case 6: result.add("Водень");
result.add("Гелій");
break;
case 7:
case 8: result.add("Метан");
result.add("Водень");
result.add("Гелій");
break;
default:
break;
}
return result;
}
Зверніть увагу: ідентичним за складом атмосфер планетам ми зіставили один і той самий код. А зробили ми це через конструкції case, що йдуть підряд.
Отже, якщо ми хочемо отримати склад атмосфери нашої з вами рідної планети, викликаємо наш метод із параметром 3:
getPlanetAtmosphere(3).
System.out.println(getPlanetAtmosphere(3)) поверне нам [Вуглекислий газ, Азот, Кисень].
Експеримент з break
Що вийде, якщо ми приберемо всі оператори break? Спробуємо на практиці:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("Немає атмосфери");
case 2:
case 4: result.add("Вуглекислий газ");
case 3: result.add("Вуглекислий газ");
result.add("Азот");
result.add("Кисень");
case 5:
case 6: result.add("Водень");
result.add("Гелій");
case 7:
case 8: result.add("Метан");
result.add("Водень");
result.add("Гелій");
default:
}
return result;
}
Якщо ми роздрукуємо результат роботи методу System.out.println(getPlanetAtmosphere(3))
, то наша рідна планета виявиться не такою вже придатною для життя. Або придатною? Судіть самі:
[Вуглекислий газ, Азот, Кисень, Водень, Гелій, Метан, Водень, Гелій]
Чому так вийшло? Програма виконала всі case після першого збігу і до кінця блоку switch.
Зайва оптимізація break
Зауважимо, що ми можемо вдосконалити метод іншим розташуванням директив break і варіантів вибору:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("Немає атмосфери");
break;
case 3: result.add("Азот");
result.add("Кисень");
case 2:
case 4: result.add("Вуглекислий газ");
break;
case 7:
case 8: result.add("Метан");
case 5:
case 6: result.add("Водень");
result.add("Гелій");
}
return result;
}
Виглядає коротшим, чи не так? Ми скоротили загальну кількість операторів, погравшись із порядком проходження case і перегрупуванням. Тепер кожен вид газу додається до списку тільки в одному рядку коду.
Лістинг останнього прикладу методу наведено тільки для демонстрації роботи, вкрай не рекомендується писати в подібному стилі. Якщо автору (а тим паче стороннім програмістам) схожого коду доведеться його супроводжувати, то буде вельми важко відновити логіку формування блоків вибору і коду, що виконується, для оператора switch java.
Відмінності від if
Незважаючи на зовнішню схожість операторів if і switch, не забувайте, що вибір варіантів виконання оператора множинного вибору switch ґрунтується на КОНКРЕТНОМУ ЗНАЧЕНННІ, тоді як в if. може бути будь-який логічний вираз. Зважайте на цей факт, проєктуючи ваш код. Давайте трохи докладніше розглянемо нововведення для switch у різних версіях Java.Switch у Java 7
До Java 7 як значення для перемикача можна було використовувати byte, short, char і int примітиви. Також була підтримка enum і обгорток перерахованих вище примітивних типів: Character, Byte, Short, и Integer. Але ж часто нам потрібно знайти значення java switch string! Як би це виглядало в Java 6:
DayOfWeek day = DayOfWeek.fromValue("Thursday");
switch (day) {
case MONDAY:
System.out.println("Сьогодні вітряно!");
break;
case THURSDAY:
System.out.println("Сьогодні сонячно!");
break;
case WEDNESDAY:
System.out.println("Сьогодні дощ!");
break;
default:
System.out.println("Ой, щось не так!");
І enum:
public enum DayOfWeek {
MONDAY("Monday"),
THURSDAY ("Четвер"),
WEDNESDAY("Wednesday"),
NOT_FOUND("Not found");
private final String value;
DayOfWeek(final String value) {
this.value = value;
}
public static DayOfWeek fromValue(String value) {
for (final DayOfWeek dayOfWeek : values()) {
if (dayOfWeek.value.equalsIgnoreCase(value)) {
return dayOfWeek;
}
}
return NOT_FOUND;
}
}
Але починаючи з Java 7 додалася можливість використовувати тип String як значення для перемикача switch:
String day = "Thursday";
switch (day) {
case "Monday":
System.out.println("Сьогодні вітряно!");
break;
case "Thursday":
System.out.println("Сьогодні сонячно!");
break;
case "Wednesday":
System.out.println("Сьогодні дощ!");
break;
default:
System.out.println("Ой, щось не так!");
}
Незважаючи на нові можливості, підхід з використанням enum більш гнучкий і рекомендований до використання: цей enum ми можемо перевикористовувати багато разів.
Switch у Java 12
У Java 12 було покращено вирази Switch для зіставлення зі взірцем. Якщо використовувати Switch як і в прикладі вище, для задавання значення деякої змінної ми повинні були обчислити значення і присвоїти заданій змінній, а потім використовувати break:
int count = 2;
int value;
switch (count) {
case 1:
value = 12;
break;
case 2:
value = 32;
break;
case 3:
value = 52;
break;
default:
value = 0;
}
Але завдяки можливостям 12-ї версії Java ми можемо переписати цей вираз в такий спосіб:
int value = switch (count) {
case 1:
break 12;
case 2:
break 32;
case 3:
break 52;
default:
break 0;
};
Давайте трохи пройдемося зміненими моментами:
Якщо раніше ми задавали змінній значення всередині блоків case, оскільки сам оператор switch не міг нічого повертати, зараз така можливість у нас є, і ми безпосередньо за допомогою switch повертаємо значення.
Раніше праворуч від break у нас уже нічого не могло стояти, а зараз ми його використовуємо як оператор return для повернення значення нашим switch. Мітки з двокрапкою відзначають точку входу в блок операторів. Тобто з того місця починається виконання всього коду нижче, навіть тоді, коли зустрічається інша мітка.
Як підсумок – наскрізний перехід від мітки до мітки, який ще називають провалюванням (fall-through).

int count = 2;
int value = switch (count) {
case 1 -> 12;
case 2 -> 32;
case 3 -> 52;
default -> 0;
};
Код став значно простішим, чи не так?
І ще: лямбда-оператор може слугувати і типовим аналогом двокрапки, після якої йде цілий блок із деякими операціями:
int count = 2;
int value = switch (count) {
case 1 -> {
//деякі обчислювальні операції...
break 12;
}
case 2 -> {
//деякі обчислювальні операції...
break 32;
}
case 3 -> {
//деякі обчислювальні операції...
break 52;
}
default -> {
//деякі обчислювальні операції...
break 0;
}
};
Ну а що якщо у нас для деяких кейсів значення, що повертається, буде однаковим?
Вийде, що у нас фактично однакові кейси для деяких різних значень. Як би це можна було б скоротити за допомогою нових можливостей Java 12:
int count = 2;
int value = switch (count) {
case 1, 3, 5 -> 12;
case 2, 4, 6 -> 52;
default -> 0;
};
Switch у Java 13
У Java 13 змінився спосіб повернення значення з switch. Якщо в java 12 значення, що повертається, ми писали після break, який слугував у нас як return для блоку switch, то зараз повертатимемо значення за допомогою слова yield. Дивимося:
int value = switch (count) {
case 1:
yield 12;
case 2:
yield 32;
case 3:
yield 52;
default:
yield 0;
};
У той же час, код, написаний на java 12 з використанням break для повернення, компілюватися не буде(((

Загалом
- Використовуйте оператор case за кількості розгалужень понад два, щоб не захаращувати if-структурами код.
- Не забувайте завершувати логічний блок кожної гілки, що відповідає конкретному значенню (блок case) викликом break.
- Оператор switch, як вираз, крім деяких примітивних типів може використовувати також типи Enum і String.
- Пам'ятайте про блок default – використовуйте його для обробки незапланованих значень вибору.
- Для оптимізації продуктивності перемістіть гілки коду з варіантами вибору, які найчастіше зустрічаються, в початок блоку switch.
- Не захоплюйтеся «оптимізацією» через видалення break наприкінці блоку вибору case – такий код складний для розуміння, і, як наслідок, його важко супроводжувати під час розвитку.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ