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
32 changes: 29 additions & 3 deletions modules/90-loops/200-aggregation-strings/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Агрегация применяется не только к числам, но и к строкам.
Агрегация применяется не только к числам, но и к строкам. Под агрегацией строк понимают задачи, в которых заранее неизвестно, что содержат строки и какого они размера.

При агрегации строка формируется динамически, то есть заранее неизвестно, какого она размера и что будет содержать. Представьте себе метод, который умеет умножать строку — то есть он повторяет ее указанное количество раз:
При агрегации строка формируется динамически. Представьте себе метод, который повторяет строку указанное количество раз. В Java для этого есть готовые средства, но здесь мы посмотрим, как такой повтор устроен внутри:

```java
App.repeat("hexlet", 3); // "hexlethexlethexlet"
Expand All @@ -10,7 +10,7 @@ App.repeat("hexlet", 3); // "hexlethexlethexlet"

```java
public static String repeat(String text, int times) {
// Нейтральный элемент для строк пустая строка
// Нейтральный элемент для строк пустая строка
var result = "";
var i = 1;

Expand All @@ -33,3 +33,29 @@ result = result + "hexlet"; // "hexlet"
result = result + "hexlet"; // "hexlethexlet"
result = result + "hexlet"; // "hexlethexlethexlet"
```

Наглядно процесс наращивания строки выглядит так:

```text
repeat("hexlet", 3):

i=1: result = "" + "hexlet" = "hexlet"
i=2: result = "hexlet" + "hexlet" = "hexlethexlet"
i=3: result = "hexlethexlet" + "hexlet" = "hexlethexlethexlet"
└── результат
```

Здесь работают сразу две переменные. Счетчик `i` управляет количеством повторов и останавливает цикл, когда повторов набралось `times`. Переменная `result` хранит накопленную строку и отдает ее вызывающему коду после цикла.

## Нейтральный элемент

Чтобы наращивание заработало, нужно стартовое значение. Для строк им служит **пустая строка** `""`.

Ее называют нейтральным элементом, потому что при конкатенации она ничего не меняет:

```java
System.out.println("" + "abc"); // => abc
System.out.println("abc" + ""); // => abc
```

Поэтому пустая строка всегда стоит в начале при агрегации строк. С нее цикл начинает наращивание, а дальше на каждой итерации добавляет к результату очередной кусок.
7 changes: 6 additions & 1 deletion modules/90-loops/200-aggregation-strings/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
name: Агрегация данных (Строки)
tips: []
tips:
- |
[Итерация](https://ru.wikipedia.org/wiki/Итерация_(программирование))
definitions:
- name: Агрегация
description: Накопление результата во время итераций и работа с ним после цикла.
45 changes: 40 additions & 5 deletions modules/90-loops/250-iteration-over-strings/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
Циклы подходят не только для обработки чисел, но и при работе со строками. В первую очередь благодаря возможности получить конкретный символ по его индексу. Ниже пример кода, который распечатывает буквы каждого слова на отдельной строке:
С помощью циклов обрабатывают числа и работают со строками. Строка состоит из символов, и до каждого символа можно добраться по его индексу. Индексы начинаются с нуля, поэтому первый символ строки `"Arya"` имеет индекс `0`, а последний — индекс `length() - 1`.

Получить символ по индексу позволяет метод `charAt()`, а узнать длину строки — метод `length()`. Этих двух методов и счетчика достаточно, чтобы пройти строку символ за символом. Ниже пример кода, который печатает буквы слова на отдельных строках:

```java
public static void printNameBySymbol(String name) {
var i = 0;
// Такая проверка будет выполняться до конца строки
// Такая проверка выполняется до конца строки,
// включая последний символ. Его индекс `length() - 1`.
while (i < name.length()) {
// Обращаемся к символу по индексу
System.out.println(name.charAt(i));
i += 1;
i = i + 1;
}
}

Expand All @@ -20,9 +22,42 @@ App.printNameBySymbol(name);
// "a"
```

Самое главное в этом коде — поставить правильное условие в `while`. Это можно сделать сразу двумя способами:
Цикл проходит по каждому символу строки по очереди:

```text
"Arya"
│ │ │ │
A r y a
↓ ↓ ↓ ↓
каждый символ обрабатывается по очереди
```

Главное в этом коде — поставить правильное условие в `while`. Сделать это можно двумя способами:

* `i < name.length()`
* `i <= name.length() - 1`

Оба способа приводят к одному результату.
Оба способа приводят к одному результату. Первый встречается чаще, потому что в нем меньше арифметики.

## Обход в обратном порядке

Счетчик не обязан расти от нуля. Если начать с последнего индекса и уменьшать его до нуля, строка пройдется задом наперед. Напишем метод, который печатает символы слова в обратном порядке:

```java
public static void printReversed(String name) {
// Начинаем с последнего символа
var i = name.length() - 1;
while (i >= 0) {
System.out.println(name.charAt(i));
i = i - 1;
}
}

App.printReversed("Arya");
// "a"
// "y"
// "r"
// "A"
```

Здесь счетчик `i` стартует со значения `name.length() - 1`, двигается к нулю и завершает цикл, когда становится меньше нуля. На каждом шаге метод берет символ по текущему индексу и печатает его. Направление обхода задает только начальное значение счетчика и способ его изменения.
4 changes: 3 additions & 1 deletion modules/90-loops/250-iteration-over-strings/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
---
name: Обход строк
tips: []
tips:
- |
[Итерация](https://ru.wikipedia.org/wiki/Итерация_(программирование))
52 changes: 34 additions & 18 deletions modules/90-loops/300-conditions-inside-loops/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
Тело цикла, как и тело метода — это место выполнения инструкций. Значит, мы можем использовать внутри него все изученное ранее — в том числе условные конструкции.
Тело цикла, как и тело метода — это место выполнения инструкций. Значит, внутри него работает все изученное раньше, в том числе условные конструкции. Так программа повторяет одно действие много раз, но на каждом повторе принимает решение.

Рассмотрим метод, который считает, сколько раз входит буква в предложение:
Цикл перебирает значения подряд, а условие внутри цикла решает, что делать с текущим значением. Рассмотрим метод, который считает, сколько раз буква входит в предложение:

```java
countChars("Fear cuts deeper than swords.", 'e'); // 4
// Если вы ничего не нашли, то результат — 0 совпадений
countChars("Sansa", 'y'); // 0
App.countChars("Fear cuts deeper than swords.", 'e'); // 4
// Если ничего не нашли, то результат — 0 совпадений
App.countChars("Sansa", 'y'); // 0
```

Сначала попробуйте ответить на вопросы:

* Является ли эта операция агрегацией?
* Какой будет проверка на вхождение символа?

А теперь посмотрим на фрагмент кода:
А теперь посмотрим на код:

```java
public static int countChars(String str, char ch) {
var i = 0;
var count = 0;
while (i < str.length()) {
if (str.charAt(i) == ch) {
// Считаем только подходящие символы
count = count + 1;
var i = 0;
var count = 0;
while (i < str.length()) {
if (str.charAt(i) == ch) {
// Считаем только подходящие символы
count = count + 1;
}
// Счетчик увеличивается в любом случае
i = i + 1;
}
// Счетчик увеличивается в любом случае
i = i + 1;
}

return count;
return count;
}
```

Эта задача является агрегирующей. Метод считает не все символы, но при этом для подсчета самой суммы все равно приходится анализировать каждый символ.
Это агрегирующая задача. Метод считает не все символы, но для подсчета суммы все равно приходится посмотреть каждый. Переменная `count` хранит результат и растет только тогда, когда текущий символ совпал с искомым.

Ключевое отличие этого цикла от рассмотренных в наличии условия внутри тела. Переменная `count` увеличивается только в том случае, когда текущий рассматриваемый символ совпадает с ожидаемым. В остальном — это типичный агрегатный метод, который возвращает количество нужных символов вызываемому коду.
## Счетчик и условие отвечают за разное

В таком цикле удобно разделять две части. Счетчик `i` переводит программу к следующему символу, а `if` решает, что делать с текущим. Счетчик меняется на каждой итерации, а действие внутри `if` выполняется не всегда.

Это важно. Если увеличивать `i` только внутри `if`, цикл застрянет на первом неподходящем символе, потому что счетчик перестанет расти и условие `i < str.length()` навсегда останется истинным. Программа зациклится. Поэтому строка `i = i + 1` стоит снаружи `if` и выполняется при любом исходе проверки.

## Работа по шагам

Разберем вызов `countChars("Sansa", 'a')`. До цикла `i` равен `0`, а `count` равен `0`.

**Шаг 1.** Условие `i < str.length()` истинно. Символ с индексом `0` — это `S`. Он не равен `a`, блок `if` не выполняется. Затем `i` растет до `1`.

**Шаг 2.** Условие снова истинно. Символ с индексом `1` — это `a`. Он совпал с искомым, поэтому `count` растет до `1`. Затем `i` растет до `2`.

Дальше цикл проверяет каждый символ. Подходящие он считает, остальные пропускает. Когда `i` станет равен длине строки, условие цикла станет ложным, и метод вернет накопленное значение `count`.

Условие внутри цикла может проверять что угодно — четность числа, совпадение символа, длину строки или значение переменной. Главное, чтобы счетчик продолжал меняться и цикл мог завершиться.
71 changes: 64 additions & 7 deletions modules/90-loops/400-syntax-sugar/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,66 @@
Подобные конструкции `index = index + 1` в Java используются довольно часто, поэтому создатели языка добавили сокращенный вариант записи: `index += 1`. Такие сокращения принято называть **синтаксическим сахаром**, потому что они делают процесс написания кода немного проще и приятнее.
В программировании часто встречаются повторяющиеся конструкции. В Java, как и во многих других языках, их запись можно сократить. Такие упрощения называют **синтаксическим сахаром**. Они делают написание кода короче и приятнее, сохраняя тот же результат.

Существуют сокращенные формы для всех арифметических операций и для конкатенации строк:
## Сокращенные формы присваивания

* `a = a + 1` → `a += 1`
* `a = a - 1` → `a -= 1`
* `a = a * 2` → `a *= 2`
* `a = a / 1` → `a /= 1`
* `a = a + "foo"` → `a += "foo"`
Часто значение переменной меняют, прибавив или вычтя что-то, умножив или разделив на число. Базовый вариант выглядит так:

```java
index = index + 1;
count = count * 2;
total = total - 5;
price = price / 3;
```

Java позволяет записать то же самое короче, с помощью составных операторов:

```java
index += 1; // то же самое, что index = index + 1
count *= 2; // то же самое, что count = count * 2
total -= 5; // то же самое, что total = total - 5
price /= 3; // то же самое, что price = price / 3

Check notice on line 20 in modules/90-loops/400-syntax-sugar/ru/README.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] modules/90-loops/400-syntax-sugar/ru/README.md#L20

Possible typo: you repeated a word (ENGLISH_WORD_REPEAT_RULE) Suggestions: `index` Rule: https://community.languagetool.org/rule/show/ENGLISH_WORD_REPEAT_RULE?lang=en-US Category: MISC
Raw output
modules/90-loops/400-syntax-sugar/ru/README.md:20:52: Possible typo: you repeated a word (ENGLISH_WORD_REPEAT_RULE)
 Suggestions: `index`
 Rule: https://community.languagetool.org/rule/show/ENGLISH_WORD_REPEAT_RULE?lang=en-US
 Category: MISC
```

Каждый такой оператор берет текущее значение переменной, применяет операцию и сохраняет результат в ту же переменную. Слева всегда стоит имя переменной, в которую запишется новое значение.

## Сахар в циклах

В циклах такие сокращения встречаются особенно часто. В них обычно меняют счетчик и накапливают результат:

Check notice on line 27 in modules/90-loops/400-syntax-sugar/ru/README.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] modules/90-loops/400-syntax-sugar/ru/README.md#L27

Unpaired symbol: ‘"’ seems to be missing (EN_UNPAIRED_QUOTES) URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US Category: PUNCTUATION
Raw output
modules/90-loops/400-syntax-sugar/ru/README.md:27:26: Unpaired symbol: ‘"’ seems to be missing (EN_UNPAIRED_QUOTES)
 URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses 
 Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US
 Category: PUNCTUATION

Check notice on line 27 in modules/90-loops/400-syntax-sugar/ru/README.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] modules/90-loops/400-syntax-sugar/ru/README.md#L27

Unpaired symbol: ‘"’ seems to be missing (EN_UNPAIRED_QUOTES) URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US Category: PUNCTUATION
Raw output
modules/90-loops/400-syntax-sugar/ru/README.md:27:70: Unpaired symbol: ‘"’ seems to be missing (EN_UNPAIRED_QUOTES)
 URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses 
 Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US
 Category: PUNCTUATION

```java
var sum = 0;
var index = 1;

while (index <= 5) {
sum += index; // то же самое, что sum = sum + index
index += 1; // то же самое, что index = index + 1
}

System.out.println(sum); // => 15
```

Без сокращений тело цикла было бы длиннее и многословнее:

```java
while (index <= 5) {
sum = sum + index;
index = index + 1;
}
```

## Конкатенация строк

Составные операторы работают не только с числами. Для строк подходит `+=`, потому что `+` соединяет строки:

```java
var text = "Hello";
text += " World"; // то же самое, что text = text + " World"
// "Hello World"
```

Поэтому при сборке строки в цикле счетчик меняют через `+=`, а к результату каждый раз дописывают очередной символ тем же оператором.

## Поддерживаемые сокращения

Сокращенная форма есть почти у всех операторов: `+=`, `-=`, `*=`, `/=`, `%=`. Все они работают по одному принципу — берут текущее значение переменной, применяют операцию и кладут результат обратно.

Отдельно стоит изменение переменной на единицу. Запись `index += 1` можно сократить до `index++`, а `index -= 1` — до `index--`. Эти две операции называют инкрементом и декрементом, у них есть свои тонкости, и им посвящен отдельный разговор.
9 changes: 8 additions & 1 deletion modules/90-loops/400-syntax-sugar/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
---
name: Синтаксический сахар
tips: []
tips:
- |
[Синтаксический сахар](https://ru.wikipedia.org/wiki/Синтаксический_сахар)
definitions:
- name: Синтаксический сахар
description: >
это синтаксические возможности, применение которых не влияет на поведение
программы, но делает использование языка более удобным для человека.
Loading
Loading