Короткий ответ
Stream в Java 8 — это абстракция для декларативной обработки последовательностей данных: вы описываете, что нужно сделать с элементами (отфильтровать, преобразовать, агрегировать), а не как это сделать с помощью циклов. java.util.stream.Stream не хранит данные и не является коллекцией — это конвейер операций над источником (коллекцией, массивом, файлом, генератором), который обрабатывает элементы лениво и при необходимости параллельно.
Как это работает подробнее
Пайплайн стрима состоит из трёх частей: источник, промежуточные операции и терминальная операция. Промежуточные операции (filter, map, flatMap, sorted, limit, distinct, peek) ленивы: они не выполняются, пока к пайплайну не применена терминальная операция, и каждая возвращает новый стрим.
Терминальные операции (collect, forEach, reduce, count, anyMatch) запускают обработку и производят результат; после терминальной операции стрим использовать нельзя. Исходная коллекция при работе стрима не изменяется.
- map() преобразует каждый элемент один в один, а flatMap() «разворачивает» вложенные структуры в один поток элементов.
- collect() вместе с классом Collectors собирает результат: toList(), toSet(), groupingBy(), joining() и другие.
- Параллельная обработка запускается вызовом parallelStream(), но требует осторожности с общим изменяемым состоянием.
Пример кода
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> names = List.of("Анна", "Борис", "Алексей", "Ольга");
// filter -> map -> collect
List<String> result = names.stream()
.filter(name -> name.startsWith("А"))
.map(String::toUpperCase)
.collect(Collectors.toList());
// flatMap: вложенные списки в один поток
List<List<Integer>> nested = List.of(
List.of(1, 2), List.of(3, 4));
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
}
}