Ветвление это выбор одной из нескольких последовательностей действий в зависимости от условия. В Java за него отвечают операторы ![Голые ветки дерева с редкими осенними листьями на фоне синего неба: ветвление в природе]()
if (одна ветвь: выполнить или пропустить), if-else (две ветви, а с цепочкой else if сколько угодно) и switch-case (много вариантов по значению одной переменной), а для коротких выборов еще и тернарный оператор ? :. В данной статье мы рассмотрим такое понятие как ветвление в компьютерных программах в общем и написанных на ЯП Java. Поговорим о таких управляющих конструкциях, как:
if-then(или жеif)if-then-else(или жеif-else)switch-case
Кратко
- Ветвление это алгоритмическая конструкция: в зависимости от истинности условия выполняется одна из нескольких последовательностей действий.
if (условие) { … }выполняет блок только при истинном условии, иначе не делает ничего: ветвь одна; так защищаются от неверных значений вродеnull.if-elseдает ровно две ветви, а цепочкаelse ifсколько угодно: условия проверяются сверху вниз, срабатывает первое истинное, остальные уже не проверяются.switch-caseсравнивает одно значение с набором констант; в обычном switch это byte, short, int, char с их обертками, enum и String;defaultсрабатывает, если не совпало ничего.breakв конце кейса нужен, иначе выполнение «проваливается» в следующий кейс; этим пользуются, чтобы объединить несколько значений в одну ветку (case SUNDAY: case SATURDAY:).- Правило выбора: одно-два условия это
ifиif-else, диапазоны и разные условия это цепочкаelse if, много вариантов одного значения этоswitch.

Ветвление
Начнем с базовых понятий. Любая программа представляет собой набор команд, выполняемых компьютером. Чаще всего команды выполняются последовательно, друг за другом. Чуть реже (но все еще довольно часто) возникают ситуации, когда нужно изменить последовательный ход выполнения команд программы. Иногда, в зависимости от некоторых условий, бывает необходимо исполнять один блок команд вместо другого. А когда эти условия меняются, поступать наоборот. К примеру, есть ряд сайтов, посещение которых запрещено лицам, не достигшим возраста 18 лет. Обычно, при первом посещении подобного ресурса пользователя встречает некоторая форма, в которой пользователя предупреждают о возрастном ограничении и просят ввести дату его рождения. Тогда, в зависимости от данных, которые ввел пользователь, ему либо позволят войти на ресурс, либо нет. Такой функционал обеспечивается тем, что принято называть ветвлением. Приведем еще одну аналогию. Представим себя на перекрестке семи дорог. Перед нами стоит выбор: свернуть налево или направо, либо же пойти прямо. Наш выбор опирается на некоторые условия. Также у нас нет возможности идти несколькими дорогами одновременно. Т.е. в зависимости от некоторых условий, нам придется выбрать одну дорогу. Такой же принцип и с ветвлением. Теперь попробуем привести определение ветвлению. Ветвление это алгоритмическая конструкция, в которой в зависимости от истинности некоторого условия выполняется одна из нескольких последовательностей действий. Ветвление реализовано (скорее всего) абсолютно во всех языках программирования. В языке программирования Java есть несколько так называемых управляющих конструкций, благодаря которым можно реализовать ветвление в своей программе. Таких конструкций в языке программирования 3:- Оператор
if-then - Оператор
if-then-else - Оператор
switch-case
? :, но это уже выражение, которое возвращает одно из двух значений, а не оператор ветвления, поэтому о нем в отдельной статье. В данной статье мы рассмотрим операторы if-else и switch-case.
Оператор if-then
Операторif-then, или же просто if, пожалуй, самый распространенный оператор. Выражение “да там 1 if написать” уже стало крылатым.
Оператор if имеет следующую конструкцию:
if (bool_condition) {
statement
}
В данной конструкции:
bool_condition: boolean выражение, результатом которого является true или false. Данное выражение называют условием.statement: команда (может быть не одна), которую необходимо исполнить, в случае, если условие истинно (bool_condition == true)
Если (bool_condition), то {statement}
Приведем примеры:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Сколько процентов заряда батареи осталось на вашем смартфоне?");
int a = scanner.nextInt();
if (a < 10) {
System.out.println("Осталось менее 10 процентов, подключите ваш смартфон к зарядному устройству");
}
}
В данной программе пользователю предлагается ввести (с помощью класса Scanner) количество процентов заряда батареи на его смартфоне. В случае, если осталось менее 10 процентов заряда, программа предупредит пользователя о необходимости зарядить смартфон.
Это пример простейшей конструкции if. Стоит заметить, что если переменная a будет больше либо равна 10, то ничего не произойдет. Программа продолжит выполнять код, который следует за конструкцией if.
Также заметим, что в данном случае, у конструкции if есть только одна последовательность действий для исполнения: напечатать текст, либо не делать ничего. Эта вариация ветвления с одной “ветвью”.
Такое порой бывает необходимо. Например когда мы хотим обезопасить себя от неправильных значений. К примеру, мы не можем узнать количество букв в строке, если строка равна null.
Примеры ниже:
public static void main(String[] args) {
String x = null;
printStringSize(x);
printStringSize("Не представляю своей жизни без ветвлений...");
printStringSize(null);
printStringSize("Ифы это так захватывающе!");
}
static void printStringSize(String string) {
if (string != null) {
System.out.println("Кол-во символов в строке `" + string + "`=" + string.length());
}
}
В результате выполнения метода main в консоль будет выведено:
Кол-во символов в строке `Не представляю своей жизни без ветвлений...`=43
Кол-во символов в строке `Ифы это так захватывающе!`=25
Благодаря проверке на то, что string != null, нам удалось избежать ошибок в программе. И не делать ничего в тех случаях, когда переменная string была равна null.
Оператор if-then-else
Если при обычномif у программы есть выбор: “сделать что-то, либо не делать ничего”, то при if-else выбор программы сводится тому, чтобы “сделать либо одно, либо другое”. Вариант “не делать ничего” отпадает.
Вариантов исполнения (или количество ветвей) при таком виде ветвления бывает от двух и более.
Рассмотрим случай, когда варианта два. Тогда управляющая конструкция имеет следующий вид:
if (bool_condition) {
statement1
} else {
statement2
}
Здесь:
bool_condition: boolean выражение, результатом которого является true или false. Данное выражение называют условием.statement1: команда (может быть не одна), которую необходимо выполнить, если условие истинно (bool_condition == true)statement2: команда (может быть не одна), которую необходимо выполнить, если условие ложно (bool_condition == false)
Если (bool_condition), то {statement1}
Иначе {statement2}
Приведем пример:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Сколько процентов заряда батареи осталось на вашем смартфоне?");
int a = scanner.nextInt();
if (a < 10) {
System.out.println("Осталось менее 10 процентов, подключите ваш смартфон к зарядному устройству");
} else {
System.out.println("Заряда вашей батареи достаточно для того, чтобы прочитать статью на Javarush");
}
}
Тот же пример об уровне заряда батареи на смартфоне. Только если в прошлый раз программа только лишь предупреждала о необходимости зарядить смартфон, то в этот раз у нас появляется дополнительное уведомление.
Разберем этот if:
if (a < 10) {
System.out.println("Осталось менее 10 процентов, подключите ваш смартфон к зарядному устройству");
} else {
System.out.println("Заряда вашей батареи достаточно для того, чтобы прочитать статью на Javarush");
}
Если a < 10 истинно (уровень заряда батареи меньше 10), программа выведет на печать один текст. Иначе, если условие a < 10 не выполняется, то программа выведет уже совсем другой текст.
Доработаем также и второй наш пример, в котором мы выводили на экран количество букв в строке. В прошлый раз программа не выводила ничего, если переданная строка была равна null. Исправим это, превратив обычный if в if-else:
public static void main(String[] args) {
String x = null;
printStringSize(x);
printStringSize("Не представляю своей жизни без ветвлений...");
printStringSize(null);
printStringSize("Ифы это так захватывающе!");
}
static void printStringSize(String string) {
if (string != null) {
System.out.println("Кол-во символов в строке `" + string + "`=" + string.length());
} else {
System.out.println("Ошибка! Переданная строка равна null!");
}
}
В методе printStringSize в конструкцию if мы добавили блок else. Теперь, если мы запустим программу, она выведет в консоль уже не 2 строки, а 4, хотя вводные (метод main) остались такими же, как и в прошлый раз.
Текст, который выведет программа:
Ошибка! Переданная строка равна null!
Кол-во символов в строке `Не представляю своей жизни без ветвлений...`=43
Ошибка! Переданная строка равна null!
Кол-во символов в строке `Ифы это так захватывающе!`=25
Цепочка else if: несколько условий подряд
Допустимы ситуации, когда послеelse следуют не команды на исполнение, а еще один if. Тогда конструкция принимает следующий вид:
if (bool_condition1) {
statement1
} else if (bool_condition2) {
statement2
} else if (bool_conditionN) {
statementN
} else {
statementN+1
}
В данной конструкции есть несколько условий:
- bool_condition1
- bool_condition2
- bool_conditionN
- statement1
- statement2
- statementN
statement может содержать в себе 1 или более строк кода.
Условия проверяются одно за другим. Как только определится первое истинное условие, будет выполнен ряд команд, “привязанных” к истинному условию. После выполнения этих команд программа выйдет из блока if, даже если впереди были еще проверки.
Выражение “statementN+1” будет выполнено в случае, если ни одно из определенных выше условий не окажется истинным.
Данную конструкцию можно прочитать так:
Если (bool_condition1) то {statement1}
Иначе если (bool_condition2) то {statement2}
Иначе если (bool_conditionN) то {statementN}
Иначе {statementN+1}
Последняя строка в данном случае опциональна. Можно обойтись и без последнего одинокого else. И тогда конструкция примет следующий вид:
if (bool_condition1) {
statement1
} else if (bool_condition2) {
statement2
} else if (bool_conditionN) {
statementN
}
И читаться будет так:
Если (bool_condition1) то {statement1}
Иначе если (bool_condition2) то {statement2}
Иначе если (bool_conditionN) то {statementN}
Соответственно, в случае, если ни одно из условий не окажется истинным, то ни одна команда не будет исполнена.
Перейдем к примерам.
Вернемся к ситуации с уровнем заряда на смартфоне. Напишем программу, которая будет более детально информировать владельца об уровне заряда его девайса:
public static void main(String[] args) {
String alert5 = "Я скоро отключусь, но помни меня бодрым";
String alert10 = "Я так скучаю по напряжению в моих жилах";
String alert20 = "Пора вспоминать, где лежит зарядка";
String alert30 = "Псс, пришло время экономить";
String alert50 = "Хм, больше половины израсходовали";
String alert75 = "Все в порядке, заряда больше половины";
String alert100 = "Я готов к приключениям, если что..";
String illegalValue = "Такс, кто-то ввел некорректное значение";
Scanner scanner = new Scanner(System.in);
System.out.print("Сколько процентов заряда батареи осталось на вашем смартфоне?");
int a = scanner.nextInt();
if (a <= 0 || a > 100) {
System.out.println(illegalValue);
} else if (a < 5) {
System.out.println(alert5);
} else if (a < 10) {
System.out.println(alert10);
} else if (a < 20) {
System.out.println(alert20);
} else if (a < 30) {
System.out.println(alert30);
} else if (a < 50) {
System.out.println(alert50);
} else if (a < 75) {
System.out.println(alert75);
} else if (a <= 100) {
System.out.println(alert100);
}
}
К примеру в данном случае, если пользователь введет 15, то программа выведет на экран: “Пора вспоминать, где лежит зарядка”. Несмотря на то, что 15 меньше и 30 и 50 и 75 и 100, вывод на экран будет только 1.
Напишем еще одно приложение, которое будет печатать в консоль, какой сегодня день недели:
public static void main(String[] args) {
// Определим текущий день недели
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
if (dayOfWeek == DayOfWeek.SUNDAY) {
System.out.println("Сегодня воскресенье");
} else if (dayOfWeek == DayOfWeek.MONDAY) {
System.out.println("Сегодня понедельник");
} else if (dayOfWeek == DayOfWeek.TUESDAY) {
System.out.println("Сегодня вторник");
} else if (dayOfWeek == DayOfWeek.WEDNESDAY) {
System.out.println("Сегодня среда");
} else if (dayOfWeek == DayOfWeek.THURSDAY) {
System.out.println("Сегодня четверг");
} else if (dayOfWeek == DayOfWeek.FRIDAY) {
System.out.println("Сегодня пятница");
} else if (dayOfWeek == DayOfWeek.SATURDAY) {
System.out.println("Сегодня суббота");
}
}
Удобно конечно, но в глазах немного рябит от обилия однообразного текста. В ситуациях, когда у нас имеется большое количество вариантов, лучше использовать оператор, речь о котором пойдет ниже.
Оператор switch-case
Альтернативой жирнымif с большим количеством ветвей служит оператор switch-case.
Данный оператор как бы говорит “Так, у нас есть вот такая вот переменная. Смотрите, в случае, если ее значение равно `x`, то делаем то-то и то-то, если ее значение равно `y`, то делаем по-другому, а если ничему не равно из вышеперечисленного, просто делаем вот так… ”
Данный оператор обладает следующей структурой.
switch (argument) {
case value1:
statement1;
break;
case value2:
statement2;
break;
case valueN:
statementN;
break;
default:
default_statement;
break;
}
Рассмотрим данную структуру более подробно.
argument это некоторая переменная (или любое выражение), значение которой мы будем сравнивать с гипотетическими различными вариантами. Сама переменная может быть какой угодно, а вот значения в case обязаны быть константами: литералами, final-константами или элементами enum. Также стоит сказать, что обычный оператор switch поддерживает в качестве аргумента далеко не любой тип данных. Допустимые типы по спецификации языка перечислены ниже:
- byte and Byte
- short and Short
- int and Integer
- char and Character
- enum
- String
switch можно передать и любой другой объект, если в case использовать образцы (pattern matching), но это уже отдельная тема.
case value1 (value2, valueN) это значения, конкретные константы, с которыми мы сравниваем значение переменной argument. Также, каждый кейс определяет под собой набор команд, которые нужно исполнить.
statement1, statement2, statementN это команды, которые необходимо будет исполнить, если argument окажется равен одному из value. К примеру, если argument будет равен value2, то программа выполнит statement2.
default и default_statement это “значения по умолчанию”. Если argument не будет равен ни одному из представленных value, то сработает ветка default и выполнится команда default_statement.
default и default_statement являются опциональными атрибутами оператора switch-case.
break и объединение кейсов
Можно заметить, что в конце каждого case блока следует операторbreak.
Данный оператор также является опциональным и служит для того, чтобы разграничивать код различных кейсов. Порой бывает необходимо выполнять одинаковые действия в разных кейсах: тогда данные кейсы можно объединить. В таком случае ключевое слово break опускают, и структура оператора switch-case будет выглядеть следующим образом:
switch (argument) {
case value1:
statement1;
break;
case valueX:
case valueY:
statementXY;
break;
}
Стоит обратить внимание: между `case valueX:` и `case valueY:` нет оператора break.
Здесь, если argument будет равен value1, выполнится statement1. А если argument будет равен valueX либо valueY, выполнится statementXY.
switch-case на примере дней недели
Разбавим тяжелую для восприятия теорию на легкую для восприятия практику. Перепишем пример с днями недели с использованием оператораswitch-case.
public static void main(String[] args) {
// Определим текущий день недели
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
switch (dayOfWeek) {
case SUNDAY:
System.out.println("Сегодня воскресенье");
break;
case MONDAY:
System.out.println("Сегодня понедельник");
break;
case TUESDAY:
System.out.println("Сегодня вторник");
break;
case WEDNESDAY:
System.out.println("Сегодня среда");
break;
case THURSDAY:
System.out.println("Сегодня четверг");
break;
case FRIDAY:
System.out.println("Сегодня пятница");
break;
case SATURDAY:
System.out.println("Сегодня суббота");
break;
}
}
Теперь напишем программу, которая выводит информацию о том, является ли сегодняшний день будним днем или выходным, используя оператор switch-case.
public static void main(String[] args) {
// Определим текущий день недели
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
switch (dayOfWeek) {
case SUNDAY:
case SATURDAY:
System.out.println("Сегодня выходной");
break;
case FRIDAY:
System.out.println("Завтра выходной");
break;
default:
System.out.println("Сегодня рабочий день");
break;
}
}
Немного поясним.
В данной программе мы получаем enum DayOfWeek, который обозначает текущий день недели.
Далее мы смотрим, равняется ли значение нашей переменной dayOfWeek значениям SUNDAY либо SATURDAY. В случае, если это так, программа выводит “Сегодня выходной”.
Если же нет, то мы проверяем, равняется ли значение переменной dayOfWeek значению FRIDAY. В случае, если это так, программа выводит “Завтра выходной”.
Если же и в этом случае нет, то вариантов у нас немного, любой оставшийся день является будним днем, поэтому по умолчанию, если сегодня НЕ пятница, НЕ суббота и НЕ воскресенье, программа выведет “Сегодня рабочий день”.
Как switch пишется с Java 14
Все, что выше, продолжает работать в любой современной Java. Но с Java 14 (JEP 361) уswitch появилась вторая форма записи, со стрелкой. Вот тот же пример про выходные:
public static void main(String[] args) {
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
switch (dayOfWeek) {
case SUNDAY, SATURDAY -> System.out.println("Сегодня выходной");
case FRIDAY -> System.out.println("Завтра выходной");
default -> System.out.println("Сегодня рабочий день");
}
}
Две разницы сразу бросаются в глаза. Во-первых, несколько значений перечисляются через запятую в одном case, а не столбиком. Во-вторых, здесь нет ни одного break: после стрелки выполняется только то, что стоит справа от нее, и никакого проваливания в следующий кейс не бывает. Если справа нужно несколько команд, их заключают в фигурные скобки.
Кроме того, switch со стрелкой может быть не оператором, а выражением, то есть возвращать значение. Тогда результат можно сразу положить в переменную:
public static void main(String[] args) {
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
String text = switch (dayOfWeek) {
case SUNDAY, SATURDAY -> "Сегодня выходной";
case FRIDAY -> "Завтра выходной";
default -> "Сегодня рабочий день";
};
System.out.println(text);
}
Обратите внимание на точку с запятой после закрывающей скобки: это уже выражение, которым заканчивается присваивание. Для switch-выражения компилятор требует, чтобы был покрыт каждый возможный вариант, поэтому ветка default здесь обязательна (для enum ее можно опустить, только если перечислены все его элементы). Классическую форму с двоеточиями и break знать все равно нужно: ее полно в существующем коде.
Заключение
Итак, в данной статье мы разобрали что такое ветвление в компьютерной программе. А также разобрались, с помощью каких управляющих конструкций реализуется ветвление в ЯП Java. Обсудили такие конструкции, как:if-thenif-then-elseswitch-case
Какую конструкцию выбрать
Чтобы не путаться, сведем все три конструкции в одну таблицу:| Конструкция | Сколько ветвей | Что проверяет | Когда использовать |
|---|---|---|---|
if |
одна: выполнить блок или пропустить | любое логическое условие | защита от неверных значений, одно действие по условию |
if-else |
ровно две | любое логическое условие | «либо одно, либо другое» |
цепочка else if |
сколько угодно, последний else необязателен |
разные условия, в том числе диапазоны (a < 10) |
несколько взаимоисключающих проверок, диапазоны значений |
switch-case |
сколько угодно плюс default |
равенство одного значения константам | много вариантов одного значения: enum, строки, коды состояний |
Вопросы и ответы
Чем if отличается от switch и когда что использовать?
if проверяет любое логическое условие: сравнения, диапазоны, вызовы методов, комбинации через && и ||. switch умеет только одно: сравнить значение переменной с набором констант на равенство. Поэтому диапазоны вроде «заряд меньше 10» это всегда if и else if, а выбор из многих вариантов одного значения (день недели, код команды, строка из меню) читается лучше через switch: нет повторяющихся сравнений, и компилятор для enum предупредит о пропущенных вариантах.
Обязателен ли блок else?
Нет.if без else это ветвление с одной ветвью: если условие ложно, программа просто идет дальше. Так пишут проверки-предохранители, например if (string != null) перед вызовом string.length(). else нужен, когда в ложном случае тоже надо что-то сделать, а не промолчать.
Что будет, если забыть break в switch?
Выполнение «провалится» в следующий кейс: после команд совпавшегоcase выполнятся команды всех следующих кейсов подряд, пока не встретится break или конец switch. Это не ошибка компиляции, а законное поведение, которым пользуются, чтобы объединить несколько значений в одну ветку. Но чаще это просто забытый break и неверный результат. С Java 14 (JEP 361) есть форма со стрелкой case SUNDAY, SATURDAY -> …, в которой проваливания нет и break не нужен.
Какие типы можно использовать в switch?
В обычном switch с константами:byte, short, int, char и их обертки Byte, Short, Integer, Character, любой enum и String (строки с Java 7). long, float, double и boolean в качестве аргумента классического switch не принимаются. С Java 21 switch принимает любой объект, если в case стоят образцы типов (case Integer i -> …), это называется pattern matching for switch.
Можно ли в switch проверять диапазоны, например a меньше 10?
В классическом switch нет:case сравнивает только на равенство с константой, case a < 10 не скомпилируется. Для диапазонов используйте цепочку else if, как в примере с зарядом батареи. В Java 21 появились охраняемые образцы: case Integer i when i < 10 -> …, но для новичка цепочка if остается самым понятным вариантом.
Что такое тернарный оператор и заменяет ли он if-else?
Это короткая запись выбора одного из двух значений:int max = a > b ? a : b; делает то же, что if (a > b) max = a; else max = b;. Разница в том, что тернарный оператор это выражение, он обязан вернуть значение, поэтому подходит только для присваиваний и аргументов, а не для блоков команд. Вложенные тернарные операторы читаются плохо, для них лучше обычный if-else.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ