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
111 changes: 91 additions & 20 deletions modules/35-methods-using/100-methods/ru/README.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions modules/35-methods-using/100-methods/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
---
name: Методы и их вызов
tips: []
definitions:
- name: Метод
description: >-
операция, которая принадлежит объекту или классу, способна принимать
данные и возвращать результат. Метод вызывается через точку, например
`"Hexlet".length()`.
- name: Аргумент
description: >-
информация, которую метод получает при вызове. Например, `Math.max(2, 3)`
передает методу `max()` аргументы `2` и `3`.
103 changes: 87 additions & 16 deletions modules/35-methods-using/110-methods-as-expressions/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,124 @@
В программировании выражение — нечто возвращающее результат, который можно использовать.

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

```java
1 + 5 * 3;
"He" + "Let";
// Переменные могут быть частью выражения
rate * 5;
var rate = 10;
var hours = 5;
var salary = rate * hours + 100;
System.out.println(salary); // => 150
```

Особенность выражений в том, что они возвращают результат, который можно использовать — например, присвоить переменной или вывести на экран:
В программировании для этого используют понятие **выражение**. Так называют конструкцию, которая вычисляется и дает результат. В примере выше `rate * hours + 100` — это выражение. Оно составлено из переменных (`rate`, `hours`), числового литерала (`100`) и арифметических операций. Все вместе оно возвращает результат, который можно сохранить в переменную или использовать дальше.

Особенность выражений в том, что их результат всегда можно применить — присвоить переменной, передать в метод или вывести на экран:

```java
// Тут выражение это 1 + 5
var sum = 1 + 5;
System.out.println(1 + 5);
```

Но не все в программировании является выражением. Определение переменной — это инструкция, она не может быть частью выражения. То есть такой код выдаст ошибку:
Но не все в программировании является выражением. Определение переменной — это инструкция, она не может быть частью выражения. Поэтому такой код выдаст ошибку:

```java
// Бессмысленный код, который не сработает
10 + var sum = 1 + 5;
```

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

```java
var rate = 10;
var hours = 5;
var bonus = 50;
// Выражение из множества операций
var salary = (rate * hours + bonus) * 12 - 500;
System.out.println(salary);
```

Здесь несколько выражений объединены в одно, и результат стал еще сложнее. Именно так и строятся программы. Маленькие шаги складываются в большие конструкции. Поэтому в программировании невозможно заранее заучить все комбинации. Гораздо важнее понять, как выражения соединяются между собой в нужный результат.

Поговорим о методах. Вызов метода — это выражение или нет? Мы знаем, что методы возвращают результат, то есть да, они выражения. Из этого автоматически следует много интересного.
## Вызов метода как выражение

Например, мы можем использовать вызов метода прямо в математических операциях. Вот как можно получить индекс последнего символа в слове:
Поговорим о методах. Вызов метода — это выражение или нет? Мы знаем, что методы возвращают результат, значит да, вызов метода является выражением. Из этого автоматически следует много интересного.

Например, мы можем использовать вызов метода прямо в математических операциях. Вот как получить индекс последнего символа в слове:

```java
// Индексы начинаются с нуля
var name = "Java";
// Вызов метода и вычитание вместе!
// Вызов метода и вычитание вместе
var lastIndex = name.length() - 1;
System.out.println(lastIndex); // => 3
```

В этом коде нет нового синтаксиса. Мы всего лишь соединили уже известные части, опираясь на их природу. Можно пойти еще дальше:
В этом коде нет нового синтаксиса. Мы всего лишь соединили уже известные части, опираясь на их природу. Метод `length()` возвращает число `4`, из него вычитаем единицу и получаем `3`. Можно пойти еще дальше и встроить вызов прямо в вывод:

```java
System.out.println(name.length() - 1); // => 3
```

Все это справедливо для любых методов, в том числе строковых:
## Выражения как аргументы методов

Аргументом метода всегда является какое-то значение. Но значение можно не только записывать напрямую, его можно вычислять. А значит, в аргументы можно подставлять любые выражения.

```java
// Здесь аргумент println — это число 150
System.out.println(150);

// А здесь аргумент — выражение, которое сначала вычисляется
System.out.println(10 * 15); // => 150

// Можно комбинировать еще сложнее
var rate = 10;
var hours = 15;
var bonus = 50;
System.out.println(rate * hours + bonus); // => 200
```

Метод `println()` получает готовое значение и выводит его на экран. Способ получения этого значения методу безразличен. Поэтому вызовы методов отлично сочетаются с любыми выражениями.

## Вызов метода внутри метода

Раз вызов метода сам по себе является выражением, его результат можно сразу передать другому методу. Это позволяет строить еще более сложные конструкции:

```java
var name = "Java";

// Вызов name.length() возвращает 4
// Этот результат сразу используется как аргумент println()
System.out.println(name.length()); // => 4
```

Здесь `name.length()` вычисляется первым и возвращает число `4`. Затем это значение подставляется в вызов `println()`. Чтобы правильно читать такие конструкции, нужно помнить про порядок вычисления.

1. Сначала выполняется метод, который находится "внутри", в нашем случае `name.length()`.
2. Затем его результат подставляется на место вызова.
3. После этого выполняется внешний метод, в нашем случае `println()`.

Код `System.out.println(name.length())` можно мысленно разложить так:

```text
System.out.println("Java".length())

Шаг 1: "Java".length() → 4
Шаг 2: println(4) → выводит 4
```

Этот принцип работает всегда. Сначала вычисляются вложенные вызовы, потом внешний.

## Методы в составе выражений

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

```java
var name = "Java";
// toUpperCase() переводит слово в верхний регистр
// toUpperCase() переводит слово в верхний регистр
System.out.println("Привет " + name.toUpperCase()); // => Привет JAVA

// Можно использовать результат метода в арифметике
var text = "hexlet";
var doubled = text.length() * 2;
System.out.println(doubled); // => 12
```

Здесь вызовы `name.toUpperCase()` и `text.length()` — это полноценные выражения. Они возвращают значения, которые комбинируются со строками, числами, переменными и другими операциями.
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
---
name: Вызов метода — выражение
definitions:
- name: Выражение
description: >-
последовательность действий над данными, которая приводит к результату,
и его можно использовать дальше.
48 changes: 41 additions & 7 deletions modules/35-methods-using/115-string-immutability/ru/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,62 @@
System.out.println(company); // => ?
```

Кажется, что ответом будет `"HEXLET"`, но это не так. Эта программа выведет `"hexlet"` (проверьте на [tryjshell](https://onecompiler.com/jshell)). Почему?
Кажется, что ответом будет `"HEXLET"`, но это не так. Эта программа выведет `"hexlet"`. Почему?

Дело в том, что строки в Java неизменяемы. Не существует способа и методов, способных изменить саму строку. Любой метод строки может только вернуть новую строку.
Дело в том, что строки в Java **неизменяемы** (или **иммутабельны**). После создания их содержимое нельзя изменить. Не существует методов, способных поменять саму строку. Любой метод строки только возвращает новую строку, а оригинал остается прежним.

Основная причина, почему так сделано – производительность. Строки, и другие примитивные типы данных нельзя менять практически ни в одном современном языке.
## Методы строк не меняют оригинал

Вторая причина связана с простотой кода. Когда мы не изменяем данные, а создаем новые данные на основе старых, то код проще анализировать и модифицировать. Особенно если с данными происходит много манипуляций, с этим вам еще предстоит столкнуться.
Когда мы вызываем метод у строки, кажется, что мы меняем ее. Например, переводим в верхний регистр. На самом деле метод `toUpperCase()` возвращает новую строку в верхнем регистре, а исходная строка не меняется.

Check notice on line 15 in modules/35-methods-using/115-string-immutability/ru/README.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] modules/35-methods-using/115-string-immutability/ru/README.md#L15

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/35-methods-using/115-string-immutability/ru/README.md:15:303: 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

Но как же поступать, если данные нужно поменять? Для этого достаточно заменить значение переменной:
```text
company = "hexlet"

company.toUpperCase() → "HEXLET" (новая строка)

Check notice on line 20 in modules/35-methods-using/115-string-immutability/ru/README.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] modules/35-methods-using/115-string-immutability/ru/README.md#L20

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/35-methods-using/115-string-immutability/ru/README.md:20:44: 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
company → "hexlet" (не изменилась)
```

Чтобы не потерять результат, сохраним его в переменную:

```java
var company = "hexlet";
var upper = company.toUpperCase();
System.out.println(upper); // => HEXLET
```

Если не сохранить результат метода, он просто потеряется. Другие методы работают так же:

```java
var text = " hi ";
var cleaned = text.trim();
System.out.println(cleaned); // => "hi", результат без пробелов
System.out.println(text); // => " hi ", строка не изменилась
```

Метод `trim()` вернул новую строку без пробелов по краям, но сам `text` остался прежним.

Основная причина такого поведения — производительность. Строки и другие примитивные типы данных нельзя менять почти ни в одном современном языке. Неизменяемость позволяет Java переиспользовать одинаковые строки в памяти и экономить ресурсы. Она же упрощает многопоточный код, где одни и те же данные читают сразу несколько потоков.

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

## Как менять данные

Но как же поступать, если данные нужно поменять? Для этого достаточно записать результат метода обратно в ту же переменную:

```java
var language = "JAVA";
language = language.toLowerCase();
System.out.println(language); // => java
```

С другой стороны, именно в такой ситуации можно создать новую переменную с другим именем:
Это уместно, когда суть данных не меняется. После `toLowerCase()` это тот же язык, просто в нижнем регистре.

С другой стороны, в такой ситуации можно создать новую переменную с другим именем:

```java
var language = "JAVA";
var processedLanguage = language.toLowerCase();
System.out.println(processedLanguage); // => java
```

Такой подход нередко предпочтительнее по соображениям читаемости. Переменные, которые постоянно меняются, сложнее анализировать. В итоге все зависит от задачи. С опытом придет понимание, какой подход лучше.
Такой подход нередко предпочтительнее по соображениям читаемости. Переменные, которые постоянно меняются, сложнее анализировать. Если результат метода представляет другую сущность, стоит дать ей отдельное имя. В итоге все зависит от задачи. С опытом придет понимание, какой подход лучше.
5 changes: 5 additions & 0 deletions modules/35-methods-using/115-string-immutability/ru/data.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
---
name: Неизменяемость строк
definitions:
- name: Неизменяемость
description: >-
свойство данных, при котором их содержимое нельзя изменить после
создания. Методы возвращают новые данные, а исходные остаются прежними.
Loading
Loading