0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Вспомним код из предыдущего урока, в котором мы вычисляли стоимость товаров в списке.</p>
1
<p>Вспомним код из предыдущего урока, в котором мы вычисляли стоимость товаров в списке.</p>
2
<p>Если сформулировать словами то, что здесь происходит то мы получим такой алгоритм:</p>
2
<p>Если сформулировать словами то, что здесь происходит то мы получим такой алгоритм:</p>
3
<ul><li>Извлекаем цены из списка товаров.</li>
3
<ul><li>Извлекаем цены из списка товаров.</li>
4
<li>Находим общую стоимость.</li>
4
<li>Находим общую стоимость.</li>
5
</ul><p>Если присмотреться, то можно увидеть, что первая операция очень похожа на отображение. То есть, мы здесь имеем дело не с одной сверткой, а с двумя последовательными операциями. Перепишем код таким образом.</p>
5
</ul><p>Если присмотреться, то можно увидеть, что первая операция очень похожа на отображение. То есть, мы здесь имеем дело не с одной сверткой, а с двумя последовательными операциями. Перепишем код таким образом.</p>
6
<p>Так как map() возвращает Stream, то мы можем сразу продолжить нашу цепочку вызовов.</p>
6
<p>Так как map() возвращает Stream, то мы можем сразу продолжить нашу цепочку вызовов.</p>
7
<p>В этом разделении кроется одна из ключевых особенностей использования стримов, которая помогает делать код проще и понятнее. Разделение на независимые этапы позволяет разбить сложную операцию таким образом, что на каждом этапе понадобится думать только о небольшой операции, которую легко проанализировать. Такого же эффекта нельзя добиться с циклами, так как циклы не комбинируются, каждый цикл живет своей собственной жизнью в отличие от стрима.</p>
7
<p>В этом разделении кроется одна из ключевых особенностей использования стримов, которая помогает делать код проще и понятнее. Разделение на независимые этапы позволяет разбить сложную операцию таким образом, что на каждом этапе понадобится думать только о небольшой операции, которую легко проанализировать. Такого же эффекта нельзя добиться с циклами, так как циклы не комбинируются, каждый цикл живет своей собственной жизнью в отличие от стрима.</p>
8
<p>Превращение сложной операции в набор простых требует времени на освоения, так как по началу не всегда очевидно, что операцию можно разбить. Рассмотрим еще несколько примеров, которые помогут нам начать использовать стримы правильно.</p>
8
<p>Превращение сложной операции в набор простых требует времени на освоения, так как по началу не всегда очевидно, что операцию можно разбить. Рассмотрим еще несколько примеров, которые помогут нам начать использовать стримы правильно.</p>
9
<p>Допустим, что нам надо вычислить сумму чисел списка, но только тех чисел, которые больше 5. Эта задача разбивается на две:</p>
9
<p>Допустим, что нам надо вычислить сумму чисел списка, но только тех чисел, которые больше 5. Эта задача разбивается на две:</p>
10
<ul><li>Фильтрация. Оставляем числа больше 5.</li>
10
<ul><li>Фильтрация. Оставляем числа больше 5.</li>
11
<li>Свертка. Ищем сумму.</li>
11
<li>Свертка. Ищем сумму.</li>
12
</ul><p>Предположим, что у нас есть список сотрудников какой-то компании и мы хотим посчитать количество денег, которые тратятся на зарплаты в одном из подразделений. Эта задача распадается на три этапа.</p>
12
</ul><p>Предположим, что у нас есть список сотрудников какой-то компании и мы хотим посчитать количество денег, которые тратятся на зарплаты в одном из подразделений. Эта задача распадается на три этапа.</p>
13
<ul><li>Фильтрация. Оставляем сотрудников только для нужного подразделения.</li>
13
<ul><li>Фильтрация. Оставляем сотрудников только для нужного подразделения.</li>
14
<li>Отображение. Извлекаем зарплату.</li>
14
<li>Отображение. Извлекаем зарплату.</li>
15
<li>Свертка. Считаем общую сумму.</li>
15
<li>Свертка. Считаем общую сумму.</li>
16
</ul><h2>Ленивое выполнение</h2>
16
</ul><h2>Ленивое выполнение</h2>
17
<p>Глядя на последний пример, может возникнуть вопрос, а не слишком ли расточительно обходить столько раз список, во время фильтрации, во время отображения и при свертке? В действительности список обходится ровно один раз. Происходит это потому, что стримы в Java<em>ленивые</em>. То есть, несмотря на вызов методов filter() и map() их реальный вызов не начинается до тех пор, пока эти данные не понадобятся. При этом внутри все реализовано таким образом, что выполняется один проход, во время которого данные пропускаются через всю цепочку функций.</p>
17
<p>Глядя на последний пример, может возникнуть вопрос, а не слишком ли расточительно обходить столько раз список, во время фильтрации, во время отображения и при свертке? В действительности список обходится ровно один раз. Происходит это потому, что стримы в Java<em>ленивые</em>. То есть, несмотря на вызов методов filter() и map() их реальный вызов не начинается до тех пор, пока эти данные не понадобятся. При этом внутри все реализовано таким образом, что выполняется один проход, во время которого данные пропускаются через всю цепочку функций.</p>
18
<p>В том числе по этой причине мы вызывали toList(), когда рассматривали map() и filter(). Этот метод запускает процесс вычисления. reduce() тоже запускает вычисление, так как это терминальная операция, на которой stream обрывается.</p>
18
<p>В том числе по этой причине мы вызывали toList(), когда рассматривали map() и filter(). Этот метод запускает процесс вычисления. reduce() тоже запускает вычисление, так как это терминальная операция, на которой stream обрывается.</p>
19
19