switch со стрелкой
В классическом switch комнаты за дверями соединены проходами, и без break выполнение идёт дальше. С Java 14 у switch есть вторая форма — со стрелкой ->. В ней у каждой двери своя отдельная комната, без проходов в соседние: вошли, выполнили ветку, вышли.
public class Main {
public static void main(String[] args) {
int day = 7;
switch (day) {
case 6, 7 -> System.out.println("weekend"); // weekend
default -> System.out.println("workday");
}
}
}Давайте пройдём по программе:
switch (day)вычисляетdayи получает7.case 6, 7 ->— семёрка есть в списке, и ветка печатаетweekend.- После ветки
switchзаканчивается:breakне нужен, и доdefaultдело не доходит.
Ветки со стрелкой
Вместо двоеточия после значений стоит стрелка ->, а за ней код ветки. Разберём, как такую ветку записывают.
Одна инструкция
После стрелки пишут одну инструкцию, как в примере. Ветка выполняет её и выходит из switch. Проваливания нет, поэтому break не пишут.
Блок в фигурных скобках
Если инструкций несколько, их берут в фигурные скобки: case 6, 7 -> { … }. После закрывающей скобки ветка тоже заканчивается, и выполнение покидает switch.
Несколько значений
Значения одной ветки перечисляют через запятую: case 6, 7 ->. Это замена меткам, которые в классическом switch ставят подряд.
Стрелки и двоеточия в одном switch смешивать нельзя: компилятор ответит different case kinds used in the switch.
switch-выражение
Чаще всего switch нужен, чтобы выбрать значение: название дня, цену, текст сообщения. switch умеет и сам давать значение, как оператор ?:. Такой switch называют switch-выражением, и обычно его пишут со стрелками:
int day = 7;
String kind = switch (day) {
case 6, 7 -> "weekend";
default -> "workday";
};
System.out.println(kind); // weekendРазберём по шагам:
switch (day)выбирает веткуcase 6, 7.- Значение после стрелки,
"weekend", становится значением всегоswitch. - Это значение попадает в переменную
kind. - Точка с запятой после закрывающей скобки обязательна: вся запись — одно объявление
String kind = …;.
На собеседовании часто спрашивают, чем switch-выражение отличается от классического switch. Ждут трёх пунктов:
- оно даёт значение;
- его ветки со стрелкой не проваливаются;
- оно обязано покрыть все возможные значения.
yield
Иногда ветке нужно сделать несколько действий, прежде чем отдать значение. Тогда её берут в фигурные скобки, а значение отдают словом yield:
int day = 3;
String kind = switch (day) {
case 6, 7 -> "weekend";
default -> {
System.out.println("day " + day); // day 3
yield "workday";
}
};
System.out.println(kind); // workdayВетка default сначала печатает day 3. Затем yield "workday" отдаёт значение всему switch и завершает ветку. В ветке из одного значения yield не нужен: стрелка сама отдаёт то, что стоит после неё.
Ответ на любой случай
switch-выражение обязано дать значение при любом значении переменной, иначе в kind нечего было бы положить. Компилятор проверяет это заранее, ещё до запуска.
Здесь картинка с дверями хромает. В коридоре все двери можно пересчитать, а у типа int больше четырёх миллиардов значений. Поэтому вместо перечисления нужна ветка default — общая комната для всех дверей, которых нет в списке.
Частая ошибка
Перечислили все месяцы, но забыли default:
int month = 12;
String season = switch (month) { // ✗
case 12, 1, 2 -> "winter";
case 3, 4, 5 -> "spring";
case 6, 7, 8 -> "summer";
case 9, 10, 11 -> "autumn";
};error: the switch expression does not cover all possible input valuesВсе двенадцать месяцев на месте, но компилятор не знает, что в month бывают только числа от 1 до 12. Для него month — любой int, например 13 или -5, а для таких чисел ветки нет. Добавьте ветку default -> "unknown";, и программа скомпилируется.
Главное
- В ветке со стрелкой нет проваливания, и
breakне нужен. - Несколько значений одной ветки перечисляют через запятую:
case 6, 7 ->. switch-выражение даёт значение; из ветки в фигурных скобках его отдают черезyield.switch-выражение обязано покрыть все значения, поэтому дляintнужна веткаdefault.