switch и break
Цепочка else if подходит для разных вопросов. Но когда одну переменную сравнивают с длинным списком значений, цепочка повторяет одно и то же: light == 'g', потом light == 'y', потом ещё раз. Для такого выбора в Java есть инструкция switch.
Представьте коридор с рядом дверей. На каждой двери написано значение: 'g', 'y'. switch один раз смотрит, что лежит в переменной, и открывает дверь с таким же значением. Но комнаты за дверями соединены проходами: из своей комнаты можно пройти в следующую, а оттуда ещё дальше. Остановит вас только выход наружу, и этот выход называется break.
Вот светофор, записанный через switch:
public class Main {
public static void main(String[] args) {
char light = 'y';
switch (light) {
case 'g':
System.out.println("go");
break;
case 'y':
System.out.println("wait"); // wait
break;
default:
System.out.println("stop");
}
}
}Давайте пройдём по программе:
char light = 'y';— горит жёлтый.switch (light)один раз берёт значениеlightи ищет дверьcase 'y'.case 'g':не подходит, и его код программа пропускает.case 'y':подходит: программа входит сюда и печатаетwait.breakвыводит изswitch, поэтому кодdefaultне выполняется.
Части switch
Внутри фигурных скобок switch стоят части трёх видов.
case
Запись case 'y': называют меткой. Это дверь с надписью:
- после
caseпишут значение и двоеточие; - значение — константа, подходящая по типу к переменной в скобках
switch; - одно значение не может стоять на двух дверях: компилятор ответит
duplicate case label.
Код ветки пишут после метки, обычно на следующих строках.
break
break — выход наружу. Выполнение сразу переходит к первой инструкции после закрывающей скобки switch.
default
Метка default — дверь для всех остальных значений. Её код выполняется, когда не подошёл ни один case. В примере это любой сигнал, кроме зелёного и жёлтого. Если default нет, в таком случае не выполнится ничего.
Проваливание
Что будет, если забыть break? Выполнение не остановится в конце ветки. Оно перейдёт к коду следующей метки и выполнит его, не сравнивая значение. Это называют проваливанием.
В виджете тот же светофор: горит зелёный, а break после go убран. Нажимайте «Следующий шаг» и следите, какие строки выполняются после go.
1public class Main {2 public static void main(String[] args) {3 char light = 'g';4 switch (light) {5 case 'g':6 System.out.println("go");7 case 'y':8 System.out.println("wait");9 break;10 default:11 System.out.println("stop");12 }13 System.out.println("done");14 }15}
Переменная light хранит символ g: горит зелёный.
Проваливание продолжается до первого break или до конца switch. Метка default от него не защищает: если выполнение дошло до неё по проходу, её код тоже выполнится.
Здесь коридор неточен в одном. Человек сам решает, идти ли в соседнюю комнату. Java не решает: она идёт дальше, пока не встретит break. На собеседовании любят показать switch без break и спросить, что он выведет.
Проваливание по делу
Иногда проваливание нужно: несколько значений ведут к одному коду. Тогда метки ставят подряд, без кода между ними:
String day = "sun";
switch (day) {
case "sat":
case "sun":
System.out.println("weekend"); // weekend
break;
default:
System.out.println("workday");
}day равен "sun", и выполнение входит через метку case "sun":. Если бы day был равен "sat", оно вошло бы через метку выше и провалилось к тому же коду. Те же два значения можно записать одной меткой через запятую: case "sat", "sun":.
Какие значения подходят
switch работает не с любым типом:
- подходят целые
int,short,byteи символыchar; - подходят строки
String: меткаcase "sun"совпадает, когда в строке написаноsun; - не подходят
long,double,floatиboolean.
Частая ошибка
Забыли break в последней ветке перед default:
int choice = 1;
switch (choice) {
case 1:
System.out.println("play"); // ✗
default:
System.out.println("no such item");
}Программа печатает две строки: play и no such item. Метка case 1 совпала, break в ветке нет, и выполнение провалилось в default. Компилятор пропускает такую программу без ошибки: предупреждение possible fall-through into case javac печатает только с флагом -Xlint:all. Поставьте break после первого println, и default будет срабатывать только для неизвестного пункта меню.
Главное
switchодин раз вычисляет значение и переходит к меткеcaseс таким же значением.breakвыводит изswitch; без него выполнение проваливается в следующие ветки, не проверяя их метки.defaultвыполняется, когда не подошёл ни одинcase, или когда до него дошли проваливанием.- Классический
switchработает сint,charиString, но не сlong,doubleиboolean.