From 42084743adc97753b3e3a9ae714c15d25a85faf0 Mon Sep 17 00:00:00 2001 From: Nikolay Gagarinov Date: Wed, 24 Jun 2026 01:39:30 +0500 Subject: [PATCH] =?UTF-8?q?feat(80-conditionals):=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D1=81=20=D1=82=D0=B5=D0=BE=D1=80=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=B8=D0=B7=20Python=20=D0=B8=20=D0=B0=D0=B4=D0=B0=D0=BF?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=B4=20java?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- modules/80-conditionals/30-if/ru/README.md | 75 +++++++++- modules/80-conditionals/30-if/ru/data.yml | 4 +- .../80-conditionals/40-if-else/ru/README.md | 89 ++++++++++-- .../80-conditionals/40-if-else/ru/data.yml | 6 + .../80-conditionals/50-else-if/ru/README.md | 77 +++++++--- .../80-conditionals/50-else-if/ru/data.yml | 4 + .../60-ternary-operator/ru/README.md | 37 ++++- .../80-conditionals/80-switch/ru/README.md | 132 +++++++++++------- modules/80-conditionals/80-switch/ru/data.yml | 7 +- 9 files changed, 334 insertions(+), 97 deletions(-) diff --git a/modules/80-conditionals/30-if/ru/README.md b/modules/80-conditionals/30-if/ru/README.md index 329fed3..d309642 100644 --- a/modules/80-conditionals/30-if/ru/README.md +++ b/modules/80-conditionals/30-if/ru/README.md @@ -1,10 +1,44 @@ -Условные конструкции позволяют выполнять разный код, основываясь на логических проверках. Посмотрим на таком типичном примере: +Логические выражения умеют проверять разные условия. Но сами по себе они лишь возвращают `true` или `false`. Чтобы программа выполняла разные действия в зависимости от результата, в Java есть конструкция `if`. -* Человек хочет оплатить покупку с карты -* Если на счету есть деньги, то нужная сумма спишется автоматически -* Если денег нет, то операция будет отклонена +```java +if (5 > 3) { + System.out.println("Yes, it is true"); +} +``` + +Здесь строка `"Yes, it is true"` напечатается, потому что условие `5 > 3` истинно. + +```text +┌───────────┐ +│ условие? │ +└─────┬─────┘ + true │ + ↓ +┌───────────┐ +│ тело if │ +└───────────┘ +``` + +После слова `if` в круглых скобках записывается логическое выражение. Затем в фигурных скобках идет блок кода. Этот блок выполнится, только если условие истинно. Если оно ложно, блок пропускается, и метод продолжает работу со следующей строки. + +## Блоки кода + +Все инструкции внутри фигурных скобок образуют один блок. Они выполняются вместе, когда условие истинно. + +```java +if (10 == 10) { + System.out.println("First"); + System.out.println("Second"); +} + +System.out.println("Goodbye!"); +``` + +Здесь напечатаются `"First"` и `"Second"`, потому что условие выполнилось. А `"Goodbye!"` напечатается в любом случае, ведь эта строка уже за пределами блока. Принцип такой же, как и в определении методов. + +## Использование if внутри метода -Для примера напишем метод, который определяет тип переданного предложения. Для начала он будет отличать обычные предложения от вопросительных: +Напишем метод, который определяет тип переданного предложения. Если предложение оканчивается знаком вопроса, метод вернет `"question"`, иначе вернет `"general"`: ```java public static String getTypeOfSentence(String sentence) { @@ -19,6 +53,33 @@ App.getTypeOfSentence("Hodor"); // "general" App.getTypeOfSentence("Hodor?"); // "question" ``` -`if` — конструкция языка, управляющая порядком инструкций. В скобках ей передается логическое выражение, а затем описывается блок кода в фигурных скобках. Этот блок кода будет выполнен, только если условие выполняется. +Здесь работают сразу два `return`. Если условие внутри `if` выполняется, срабатывает `return "question"`, и метод завершается. Если условие ложно, блок пропускается, и управление переходит на строку с `return "general"`. + +У метода получается несколько точек выхода. Это частая практика. В зависимости от условия метод завершается по-разному. + +Метод `getTypeOfSentence` использует `if`, но возвращает строки, поэтому предикатом не считается. В качестве предиката рассмотрим метод, который проверяет, хватает ли денег для покупки: + +```java +public static boolean hasEnoughMoney(int balance, int price) { + if (balance >= price) { + return true; + } + + return false; +} + +App.hasEnoughMoney(100, 50); // true +App.hasEnoughMoney(30, 50); // false +``` + +## if и логические выражения + +Метод `hasEnoughMoney` мы написали через `if`. Но в таком виде он мог бы обойтись и без него, ведь результат сравнения сам по себе уже логическое выражение: + +```java +public static boolean hasEnoughMoney(int balance, int price) { + return balance >= price; +} +``` -Если условие не выполняется, то блок кода в фигурных скобках пропускается, и метод продолжает свое выполнение дальше. В нашем случае следующая строчка кода — `return "general";` — заставит метод вернуть строку и завершиться. +В простых случаях лучше сразу возвращать такое выражение. `if` нужен там, где внутри блока выполняются дополнительные действия помимо возврата результата. Чем сложнее становятся программы, тем чаще встречаются такие ситуации. diff --git a/modules/80-conditionals/30-if/ru/data.yml b/modules/80-conditionals/30-if/ru/data.yml index 11d5777..dbf5644 100644 --- a/modules/80-conditionals/30-if/ru/data.yml +++ b/modules/80-conditionals/30-if/ru/data.yml @@ -1,4 +1,6 @@ --- name: Условная конструкция (if) tips: [] -definitions: [] +definitions: + - name: Условная конструкция + description: 'способ задать условие для выполнения кода. Например, `if (x > 10) { ... }`' diff --git a/modules/80-conditionals/40-if-else/ru/README.md b/modules/80-conditionals/40-if-else/ru/README.md index c7b5123..06240e2 100644 --- a/modules/80-conditionals/40-if-else/ru/README.md +++ b/modules/80-conditionals/40-if-else/ru/README.md @@ -1,33 +1,94 @@ -Условная конструкция `if` имеет несколько разновидностей. Одна разновидность включает в себя блок, который выполняется, если условие ложно: +Конструкция `if` умеет проверять условие и выполнять блок кода, когда оно истинно. У нее есть продолжение. Ветка `else` задает блок, который выполнится, если условие в `if` оказалось ложным: ```java if (x > 5) { - // Если условие true + // Выполнится, если условие true } else { - // Если условие false + // Выполнится, если условие false } ``` -Такая структура может понадобиться при начальной инициализации значения. В примере ниже проверяется наличие `email`. Если он отсутствует, то устанавливаем значение по умолчанию, если его передали, то выполняем нормализацию: +Посмотрите на метод ниже. Он определяет тип предложения по последнему символу. Если предложение оканчивается знаком вопроса, метод вернет `Sentence is question`, иначе вернет `Sentence is general`: ```java -// Здесь приходит email +public static String getTypeOfSentence(String sentence) { + String sentenceType; -if (email.equals("")) { // Если email пустой, то ставим дефолт - email = "support@hexlet.io"; -} else { // Иначе выполняем нормализацию - email = email.trim().toLowerCase(); + if (sentence.endsWith("?")) { + sentenceType = "question"; + } else { + sentenceType = "general"; + } + + return "Sentence is " + sentenceType; } -// Здесь используем эту почту +App.getTypeOfSentence("Hodor"); // "Sentence is general" +App.getTypeOfSentence("Hodor?"); // "Sentence is question" +``` + +Мы добавили `else` и новый блок. Он выполнится, если условие в `if` окажется ложным. Слово `else` переводится как "иначе". + +```text + ┌───────────┐ + │ условие? │ + └─────┬─────┘ + true │ │ false + ↓ ↓ +┌──────────┐ ┌──────────┐ +│ тело if │ │ тело else│ +└──────────┘ └──────────┘ +``` + +В блок `else` можно вкладывать другие условия `if`: + +```java +int number = 10; + +if (number > 10) { + System.out.println("Number is greater than 10"); +} else { + if (number == 10) { + System.out.println("Number is exactly 10"); + } else { + System.out.println("Number is less than 10"); + } +} ``` -Если ветка `if` содержит `return`, то `else` становится не нужен — его можно просто опустить: +## Два способа оформить if-else + +Конструкцию `if-else` можно записать двумя способами. С помощью отрицания меняется порядок блоков: ```java -if (/* условие */) { - return /* какое-то значение */; +public static String getTypeOfSentence(String sentence) { + String sentenceType; + + if (!sentence.endsWith("?")) { + sentenceType = "general"; + } else { + sentenceType = "question"; + } + + return "Sentence is " + sentenceType; } +``` + +Чтобы конструкцию было удобнее оформлять, выбирайте проверку без отрицаний и подстраивайте содержимое блоков под нее. + +## Когда else не нужен -// Продолжаем что-то делать, потому что else не нужен +Если ветка `if` содержит `return`, то `else` можно опустить. После `return` метод завершается, и следующая строка выполнится только тогда, когда условие в `if` оказалось ложным: + +```java +public static String getTypeOfSentence(String sentence) { + if (sentence.endsWith("?")) { + return "question"; + } + + // Сюда попадаем, только если условие выше ложно + return "general"; +} ``` + +Такой стиль убирает лишнюю вложенность. Чем проще выглядит метод, тем легче читать его логику. diff --git a/modules/80-conditionals/40-if-else/ru/data.yml b/modules/80-conditionals/40-if-else/ru/data.yml index 42973c7..f1d4cd8 100644 --- a/modules/80-conditionals/40-if-else/ru/data.yml +++ b/modules/80-conditionals/40-if-else/ru/data.yml @@ -1,2 +1,8 @@ --- name: Конструкция if-else +tips: [] +definitions: + - name: else + description: >- + способ задать блок кода, который выполнится, если условие с `if` не + выполнено. diff --git a/modules/80-conditionals/50-else-if/ru/README.md b/modules/80-conditionals/50-else-if/ru/README.md index 83df36b..c4ad103 100644 --- a/modules/80-conditionals/50-else-if/ru/README.md +++ b/modules/80-conditionals/50-else-if/ru/README.md @@ -1,4 +1,30 @@ -В самой полной версии конструкция `if` содержит не только ветку `else`, но и другие условные проверки с помощью `else if`. Такой вариант используется при большом количестве проверок, которые взаимоисключают друг друга: +Метод `getTypeOfSentence` различает только вопросительные и обычные предложения. Добавим в него поддержку восклицательных предложений. Сделаем это сначала через две отдельные проверки `if`: + +```java +public static String getTypeOfSentence(String sentence) { + String sentenceType = ""; + + if (sentence.endsWith("?")) { + sentenceType = "question"; + } + + if (sentence.endsWith("!")) { + sentenceType = "exclamation"; + } else { + sentenceType = "general"; + } + + return "Sentence is " + sentenceType; +} + +App.getTypeOfSentence("Who?"); // "Sentence is general" +App.getTypeOfSentence("No"); // "Sentence is general" +App.getTypeOfSentence("No!"); // "Sentence is exclamation" +``` + +Технически этот код работает, но вопросительные предложения трактует неверно. Есть и проблема с семантикой. Наличие восклицательного знака проверяется в любом случае, даже когда уже нашелся вопросительный знак. Ветка `else` относится ко второму условию, но не к первому. Поэтому вопросительное предложение получает тип `"general"`. + +Чтобы выстроить проверки в единую цепочку, конструкция `if` поддерживает ветку `else if`. Такой вариант подходит, когда проверок много и они исключают друг друга: ```java if (/* что-то */) { @@ -12,21 +38,16 @@ if (/* что-то */) { } ``` -Здесь стоит обратить внимание на два момента: +Здесь обратите внимание на два момента: -* Ветка `else` может отсутствовать -* Количество `else if` условий может быть любым +- Ветка `else` может отсутствовать +- Количество веток `else if` может быть любым -Напишем для примера расширенный метод определяющий тип предложения. Он распознает три вида предложений: +Перепишем метод с `else if`: ```java -App.getTypeOfSentence("Who?"); // "Sentence is question" -App.getTypeOfSentence("No"); // "Sentence is general" -App.getTypeOfSentence("No!"); // "Sentence is exclamation" - -public static String getTypeOfSentence(String sentence) -{ - var sentenceType = ""; +public static String getTypeOfSentence(String sentence) { + String sentenceType; if (sentence.endsWith("?")) { sentenceType = "question"; @@ -38,12 +59,34 @@ public static String getTypeOfSentence(String sentence) return "Sentence is " + sentenceType; } + +App.getTypeOfSentence("Who?"); // "Sentence is question" +App.getTypeOfSentence("No"); // "Sentence is general" +App.getTypeOfSentence("No!"); // "Sentence is exclamation" +``` + +Теперь все условия выстроены в единую конструкцию. Оператор `else if` означает "если не выполнено предыдущее условие, но выполнено текущее". + +```text + ┌─────────────────┐ + │ условие 1? │ + └────┬────────┬───┘ + true │ │ false + ↓ ↓ +┌──────────┐ ┌─────────────────┐ +│ тело if │ │ условие 2? │ +└──────────┘ └────┬────────┬───┘ + true │ │ false + ↓ ↓ + ┌───────────┐ ┌──────────┐ + │тело else if│ │ тело else│ + └───────────┘ └──────────┘ ``` -Теперь все условия выстроены в единую конструкцию. Оператор `else if` — это «если не выполнено предыдущее условие, но выполнено текущее». Получается такая схема: +Логика метода устроена так: -- Если последний символ `?`, то "question" -- Иначе, если последний символ `!`, то "exclamation" -- Иначе "general" +- Если последний символ `?`, то тип `"question"` +- Иначе, если последний символ `!`, то тип `"exclamation"` +- Иначе тип `"general"` -В итоге выполнится только один из блоков кода, относящихся ко всей конструкции `if`. +В итоге выполнится только один из блоков, относящихся ко всей конструкции `if`. diff --git a/modules/80-conditionals/50-else-if/ru/data.yml b/modules/80-conditionals/50-else-if/ru/data.yml index 79f1f2a..af6d769 100644 --- a/modules/80-conditionals/50-else-if/ru/data.yml +++ b/modules/80-conditionals/50-else-if/ru/data.yml @@ -1,2 +1,6 @@ --- name: Конструкция else if +tips: [] +definitions: + - name: else if + description: способ задать несколько альтернативных условий. diff --git a/modules/80-conditionals/60-ternary-operator/ru/README.md b/modules/80-conditionals/60-ternary-operator/ru/README.md index a62c850..6e93534 100644 --- a/modules/80-conditionals/60-ternary-operator/ru/README.md +++ b/modules/80-conditionals/60-ternary-operator/ru/README.md @@ -14,9 +14,9 @@ App.abs(10); // 10 App.abs(-10); // 10 ``` -В Java существует конструкция, которая по своему действию аналогична конструкции *if-else*, но при этом является выражением. Она называется **тернарный оператор**. +В Java существует конструкция, которая по своему действию аналогична `if-else`, но при этом является выражением. Она называется **тернарный оператор**. -Тернарный оператор — единственный в своем роде оператор, требующий три операнда. Он помогает писать меньше кода для простых условных выражений. Наш пример выше с тернарным оператором превращается в три строки кода: +Тернарный оператор — единственный в своем роде оператор, требующий три операнда. Он помогает писать меньше кода для простых условных выражений. Наш пример выше с тернарным оператором сокращается до одной строки: ```java public static int abs(int number) { @@ -30,7 +30,34 @@ public static int abs(int number) { ? : ``` -То есть сначала мы записываем логическое выражение, а дальше два разных варианта поведения: +Сначала записывается логическое выражение, а дальше два варианта поведения: -1. Если условие истинно, выполняет вариант до двоеточия -2. Если условие ложно, выполняет вариант после двоеточия +1. Если условие истинно, вычисляется вариант до двоеточия +2. Если условие ложно, вычисляется вариант после двоеточия + +Перепишем через тернарный оператор метод, который определяет тип предложения. + +Было: + +```java +public static String getTypeOfSentence(String sentence) { + if (sentence.endsWith("?")) { + return "question"; + } + + return "general"; +} +``` + +Стало: + +```java +public static String getTypeOfSentence(String sentence) { + return sentence.endsWith("?") ? "question" : "general"; +} + +App.getTypeOfSentence("Hodor"); // "general" +App.getTypeOfSentence("Hodor?"); // "question" +``` + +Тернарный оператор можно вкладывать в другой тернарный оператор. Но это считается плохой практикой, такой код тяжело читать. diff --git a/modules/80-conditionals/80-switch/ru/README.md b/modules/80-conditionals/80-switch/ru/README.md index 197db89..6f6dc57 100644 --- a/modules/80-conditionals/80-switch/ru/README.md +++ b/modules/80-conditionals/80-switch/ru/README.md @@ -1,4 +1,4 @@ -Многие языки используют не только условную конструкцию `if`, но и `switch` в дополнение к ней. Конструкция `switch` — это специализированная версия `if`, созданная для некоторых особых ситуаций. +Многие языки используют не только условную конструкцию `if`, но и `switch` в дополнение к ней. Конструкция `switch` — это специализированная версия `if`, созданная для особых ситуаций. Например, ее стоит использовать там, где есть цепочка `if else` с проверками на равенство: @@ -14,7 +14,7 @@ if (status.equals("processing")) { } ``` -Эта составная проверка обладает одной отличительной чертой: каждая ветка здесь — это проверка значения переменной `status`. Конструкция `switch` позволяет записать этот код короче и выразительнее: +У этой составной проверки есть отличительная черта. Каждая ветка здесь проверяет значение переменной `status`. Конструкция `switch` записывает такой код короче и выразительнее: ```java switch (status) { @@ -32,75 +32,103 @@ switch (status) { } ``` -С точки зрения количества элементов, `switch` — довольно сложная конструкция. В нее входят: +```text +switch (значение) { + │ + ├── case "a" → блок 1 + ├── case "b" → блок 2 + ├── case "c" → блок 3 + └── default → блок по умолчанию +} +``` -* Внешнее описание с ключевым словом `switch`. В нем два элемента: - - Переменная, по значениям которой `switch` будет выбирать поведение - - Фигурные скобки для вариантов выбора -* Конструкции `case` и `default`, внутри которых описывается поведение для разных значений рассматриваемой переменной. Каждый `case` соответствует `if`, как в примере выше. Здесь `default` — это особая ситуация, соответствующая ветке `else` в условных конструкциях. Как и в случае с `else`, указывать `default` необязательно -* Конструкция `break`, которая предотвращает «проваливание». Если ее не указать, то после выполнения нужного `case`, выполнение перейдет к следующему `case`. Этот цикл будет повторяться до ближайшего `break` или до конца `switch` +С точки зрения количества элементов `switch` — довольно сложная конструкция. В нее входят: -Фигурные скобки в `switch` не определяют блок кода, как это было в других местах. Внутри допускается только тот синтаксис, который показан выше — там можно использовать `case` или `default`. А вот внутри каждого `case` (и `default`) ситуация другая. Здесь можно выполнять любой произвольный код: +* Внешнее описание с ключевым словом `switch`. В нем два элемента. Это переменная, по значениям которой `switch` выбирает поведение, и фигурные скобки для вариантов выбора +* Конструкции `case` и `default`, внутри которых описывается поведение для разных значений переменной. Каждый `case` соответствует `if`, как в примере выше. Здесь `default` — особая ситуация, которая соответствует ветке `else` в условных конструкциях. Как и `else`, указывать `default` необязательно +* Конструкция `break`, которая предотвращает проваливание. Без нее после нужного `case` выполнение перейдет к следующему `case`. Так будет продолжаться до ближайшего `break` или до конца `switch` + +Фигурные скобки в `switch` не определяют блок кода, как в других местах. Внутри допустим только тот синтаксис, который показан выше. Там можно использовать `case` или `default`. А вот внутри каждого `case` и `default` ситуация другая. Здесь выполняется любой произвольный код: ```java switch (count) { - case 1: - // Делаем что-то полезное - break; - case 2: - // Делаем что-то полезное - break; - default: - // Что-то делаем + case 1: + // Делаем что-то полезное + break; + case 2: + // Делаем что-то полезное + break; + default: + // Что-то делаем } ``` -Иногда результат, полученный внутри `case` — это конец выполнения метода, содержащего `switch`. В таком случае его нужно как-то вернуть наружу. Для решения этой задачи есть два способа. +## Возврат значения из switch + +Иногда результат, полученный внутри `case`, завершает работу метода, который содержит `switch`. Тогда его нужно как-то вернуть наружу. Для этого есть два способа. -Первый способ — можно создать переменную перед `switch`, заполнить ее в `case` и затем вернуть значение этой переменной наружу: +Первый способ создает переменную перед `switch`, заполняет ее в `case` и в конце возвращает наружу: ```java -class App { - public static String getExplanation(int count) { - // Объявляем переменную - String result; - - // Заполняем - switch(count) { - case 1: - result = "one"; - break; - case 2: - result = "two"; - break; - default: - result = null; - } - - // Возвращаем - return result; +public static String getExplanation(int count) { + // Объявляем переменную + String result; + + // Заполняем + switch (count) { + case 1: + result = "one"; + break; + case 2: + result = "two"; + break; + default: + result = null; } + + // Возвращаем + return result; } ``` -Второй способ проще и короче. Вместо создания переменной можно использовать `case`, внутри которого можно делать обычный возврат из метода. После `return` никакой код не выполняется, так что мы можем избавиться от `break`: +Второй способ проще и короче. Вместо переменной внутри `case` можно делать обычный возврат из метода. После `return` никакой код не выполняется, поэтому `break` тут не нужен: ```java -class App { - public static String getExplanation(int count) { - - switch(count) { - case 1: - return "one"; - case 2: - return "two"; - default: - return null; - } +public static String getExplanation(int count) { + switch (count) { + case 1: + return "one"; + case 2: + return "two"; + default: + return null; } } ``` -`Switch` хоть и встречается в коде, но технически всегда можно обойтись без него. +## switch-выражение + +У классического `switch` есть современная форма со стрелочным синтаксисом. Она называется switch-выражение и сразу возвращает значение. Каждая ветка записывается как `case значение -> результат;`. Здесь не нужны ни `break`, ни проваливание между ветками: + +```java +public static String getExplanation(int count) { + return switch (count) { + case 1 -> "one"; + case 2 -> "two"; + default -> null; + }; +} +``` + +Одна ветка отрабатывает несколько значений, если перечислить их через запятую: + +```java +String season = switch (month) { + case 12, 1, 2 -> "winter"; + case 3, 4, 5 -> "spring"; + case 6, 7, 8 -> "summer"; + default -> "autumn"; +}; +``` -Польза этой конструкции в том, что она лучше выражает намерение программиста, когда нужно проверять конкретные значения переменной. В отличие от блоков `else if`, код со `switch` становится немного длиннее, но читать его гораздо проще. +`switch` встречается в коде, но технически без него всегда можно обойтись. Польза этой конструкции в том, что она лучше выражает намерение программиста, когда нужно проверять конкретные значения переменной. По сравнению с блоками `else if` код со `switch` читается понятнее. diff --git a/modules/80-conditionals/80-switch/ru/data.yml b/modules/80-conditionals/80-switch/ru/data.yml index eac6851..5d61b7b 100644 --- a/modules/80-conditionals/80-switch/ru/data.yml +++ b/modules/80-conditionals/80-switch/ru/data.yml @@ -1,3 +1,8 @@ --- name: Конструкция Switch -definitions: [] +tips: [] +definitions: + - name: switch + description: >- + способ выбрать поведение по значению переменной через ветки `case`, + например, `switch (count) { case 1: ... }`.