Вступление
Условные операторы и циклы - очень важный инструмент в программировании. Есть немного вещей, которые мы могли бы сделать с кодом, который может выполняться только построчно.
Вот что означает «управление потоком» - руководство выполнением нашей
программы вместо того, чтобы позволить ей выполняться построчно,
независимо от каких-либо внутренних или внешних факторов. Каждый язык
программирования поддерживает некоторую форму управления потоком, если
не явно через if
s и for
s или аналогичные операторы - тогда он
неявно дает нам инструменты для создания таких конструкций, то есть
языки программирования низкого уровня обычно достигают этого эффекта с
большим go-to
командам.
Циклы были концепцией, которая использовалась задолго до того, как компьютерное программирование стало вообще чем-то, но первой, кто использовал программный цикл, была Ада Лавлейс, широко известная под своей девичьей фамилией - Байрон, при вычислении чисел Бернулли еще в 19 веке.
В Java есть несколько способов управления потоком кода:
- операторы if и if-else
- операторы переключения
- утверждения
while
иdo-while
for
иenhanced for
операторов- операторы
break
иcontinue
Заявление о переключении
Если мы хотим сравнить значение с несколькими значениями и выполнить код на основе их равенства, мы могли бы сделать что-то вроде:
String input = "someCommand";
if (input.equals("date")) {
System.out.println("The current date is: " + new Date());
} else if (input.equals("help")) {
System.out.println("The possible commands are...");
} else if (input.equals("list")) {
System.out.println("The files in this directory are...");
} else if (input.equals("exit")) {
System.out.println("Exiting application...");
} else {
System.out.println("Command Not Supported");
}
Это может быстро стать громоздким и нечитаемым. Оператор switch
был
введен нам именно для того, чтобы избежать этого, когда это возможно.
Этот оператор используется, когда у нас есть несколько разных вещей,
которые мы хотим выполнить на основе значения одного выражения:
switch(variable) {
case constant1:
// Do something if the variable is equal to constant1.
// constant1 must be of same type as variable
// or easily converted to, such as Integer -> int
break;
case constant2:
// Some code
break;
...
default:
// Some code
break;
}
Переменная, переданная в качестве switch
является переменной или
выражением, значение которого мы сравниваем. Это значение сравнивается с
каждым из значений case
Если проверяемая переменная соответствует
любому из вариантов, выполняется код, следующий за этим регистром. Мы
можем иметь столько case
сколько захотим.
Здесь мы познакомились с четырьмя новыми ключевыми словами: switch
,
case
, break
и default
.
выключатель
Оператор switch
обычно принимает переменную, хотя он также может
принимать выражение, если оно возвращает принятый тип:
// Comparing the value 5 with case values
switch(5) {
// Cases
}
int x = 5;
int y = 10;
// Comparing the value 15 with case values
switch(x+y) {
// Cases
}
// Booleans are not supported by switch statements,
// so this won't compile
switch(!true) {
// Cases
}
Если мы передадим switch
null
значение, возникнет
NullPointerException
дело
Значение case
должно быть константой времени компиляции . Это
означает, что для всех case
мы должны использовать литералы /
константы (например, «abc», 5 и т. Д.) Или переменные, которые были
объявлены final
и которым присвоено значение:
final int i = 5;
int y = 15;
final int z;
z = 25;
int x = 10;
switch(x) {
case i:
// i can't be changed at any point due to the
// `final` modifier, will compile
break;
case y:
// Won't compile as `y` isn't a compile-time constant
break;
case 10+10:
// Compiles, as 10+10 is a compile-time constant
break;
case z:
// Doesn't compile as z wasn't initialized with
// its declaration, thus it isn't considered to
// be a compile-time constant
break;
case null:
// Doesn't compile, there can't be a null case
break;
}
Все случаи должны быть уникальными, иначе код Java не будет компилироваться. Если бы случаи не были уникальными, не было бы способа узнать, какой вариант выполнить среди повторяющихся значений.
перерыв
break
используется для прерывания потока кода внутри случаев. Как
только switch
обнаружит регистр, соответствующий переданной
переменной, он приступит к выполнению кода случая до тех пор, пока не
break
либо конец самого блока switch
Например:
int ourNumber = 1;
switch(ourNumber) {
case 1:
System.out.println("One");
case 2:
System.out.println("Two");
case 3:
System.out.println("Three");
break;
case 4:
System.out.println("Four");
}
Вывод этого кода:
One
Two
Three
В этом примере поток выполнения "проваливается" от первого оператора
case (который соответствует ourNumber
) до оператора break
Иногда это может приводить к выполнению нежелательных случаев, поэтому
мы должны быть осторожны, добавляя break
, и хорошая идея - добавлять
их по умолчанию в каждом case
и удалять их позже, если мы
действительно хотим выполнить несколько вариантов для некоторых
входных данных. Более подробную информацию об break
можно найти
здесь .
Если мы действительно хотим, чтобы один и тот же код выполнялся для нескольких случаев, используется обычный шаблон:
...
case "a":
case "b":
System.out.println("Variable is equal to constant1 or constant2!");
break;
...
Это приведет к выполнению System.out.println
если наша переменная
равна либо "a"
либо если она равна "b"
.
По умолчанию
default
- это фрагмент кода, который switch
если переменная, которую
мы ему передали, не соответствует ни одному из заданных случаев. Этот
оператор является необязательным, но настоятельно рекомендуется во
избежание ситуаций, когда пользовательский ввод прерывает весь поток
приложения.
Принимаемые типы данных
variable
переданная в качестве switch
может быть одной из следующих:
- символ
- байт
- короткая
- int
- Целое число
- короткий
- Байт
- Персонаж
- перечислить
- Нить
Это огромный скачок по if
и else-if
, которые поддерживают только
boolean
выражения.
При этом мы можем легко переписать if
/ if-else
из начала этой
статьи:
switch("someCommand") {
case "date":
System.out.println("The current date is: " + new Date());
break;
case "help":
System.out.println("The possible commands are...");
break;
case "list":
System.out.println("The files in this directory are...");
break;
case "exit":
System.out.println("Exiting application...");
break;
default:
System.out.println("Command Not Supported");
break;
}
Или, в качестве другого примера, мы могли бы передать целое число и
заменить эту цепочку if
и else-if
более читаемым аналогом:
int ourNumber = 4;
if (ourNumber == 1) {
System.out.println("One");
}
else if (ourNumber == 2) {
System.out.println("Two");
}
else if (ourNumber == 3) {
System.out.println("Three");
}
else if (ourNumber == 4) {
System.out.println("Four");
}
else {
System.out.println("Larger than 4");
}
Эквивалентный switch
будет выглядеть следующим образом:
switch(ourNumber) {
case 1:
System.out.println("One");
break;
case 2:
System.out.println("Two");
break;
case 3:
System.out.println("Three");
break;
case 4:
System.out.println("Four");
break;
default:
System.out.println("Larger than 4");
break;
}
Понятно, что если ourNumber
равно 1, то код после case 1:
будет
выполнен, и на стандартный вывод будет выведено «One».
Примечание. В отличие от других типов данных, строки сравниваются не
с ==
, а с .equals()
при проверке всех случаев. Это сделано для
того, чтобы сравнивать фактическое значение строк, а не расположение в
памяти.
Вложенные операторы переключения
Мы можем вложить несколько операторов switch
switch(var1) {
case constant1:
switch(var2) {
// ...
}
break;
case constant2:
...
}
Лямбда-выражения
В Java 12 есть новый, более лаконичный способ обработки switch
с
помощью лямбда-выражений.
При switch
разрывы больше не нужны, а возвращаемое значение становится
более читаемым. В настоящее время это доступно только в качестве
предварительного просмотра . Типичный переключатель нового типа будет
выглядеть примерно так:
switch(ourNumber) {
case 7, 3, 8, 4 -> System.out.println("Very popular lucky number");
case 5, 13, 9, 6 -> System.out.println("Kind of popular lucky number");
default -> System.out.println("Not all that popular");
}
// Or something like:
String s = switch(ourNumber) {
case 7, 3, 8, 4 -> "Very popular lucky number";
// ...
}
System.out.println(s);
Заключение
Управление потоком в коде необходимо абсолютно для каждого приложения. Заявления, которые изменяют поток кода, являются фундаментальными строительными блоками, и каждый начинающий разработчик должен полностью контролировать / осознавать, как они работают.