Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 68 additions & 7 deletions modules/80-conditionals/30-if/ru/README.md
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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` нужен там, где внутри блока выполняются дополнительные действия помимо возврата результата. Чем сложнее становятся программы, тем чаще встречаются такие ситуации.
4 changes: 3 additions & 1 deletion modules/80-conditionals/30-if/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
---
name: Условная конструкция (if)
tips: []
definitions: []
definitions:
- name: Условная конструкция
description: 'способ задать условие для выполнения кода. Например, `if (x > 10) { ... }`'
89 changes: 75 additions & 14 deletions modules/80-conditionals/40-if-else/ru/README.md
Original file line number Diff line number Diff line change
@@ -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";
}
```

Такой стиль убирает лишнюю вложенность. Чем проще выглядит метод, тем легче читать его логику.
6 changes: 6 additions & 0 deletions modules/80-conditionals/40-if-else/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
---
name: Конструкция if-else
tips: []
definitions:
- name: else
description: >-
способ задать блок кода, который выполнится, если условие с `if` не
выполнено.
77 changes: 60 additions & 17 deletions modules/80-conditionals/50-else-if/ru/README.md
Original file line number Diff line number Diff line change
@@ -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 (/* что-то */) {
Expand All @@ -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";
Expand All @@ -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`.
4 changes: 4 additions & 0 deletions modules/80-conditionals/50-else-if/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
---
name: Конструкция else if
tips: []
definitions:
- name: else if
description: способ задать несколько альтернативных условий.
Loading
Loading