Терминальные операции
Терминальная операция запускает pipeline
Пока у цепочки есть только промежуточные операции, она лишь описывает будущую работу. Терминальная операция запускает обработку и завершает stream. После неё тот же stream повторно использовать нельзя.
Получить коллекцию, количество или выполнить действие
toList() собирает элементы в список,
count() возвращает их количество,
а forEach() выполняет действие для элементов.
List<String> names = List.of("Ann", "Bob", "Alexander");
long count = names.stream()
.filter(name -> name.length() > 3)
.count();
Результат count равен 1.
Если нужен именно список, ту же цепочку можно закончить вызовом toList().
Проверки и поиск могут завершиться раньше
anyMatch, allMatch и noneMatch
проверяют элементы по условию. findFirst и findAny
ищут элемент. Эти операции не обязаны проходить весь stream, если ответ уже известен.
boolean hasLongName = names.stream()
.anyMatch(name -> name.length() > 8);
Как только находится подходящая строка, дальнейший проход может не понадобиться.
Результат поиска возвращается через Optional,
потому что подходящего элемента может не быть. Сам Optional подробно разберём позже в этом разделе.
min, max и reduce сворачивают элементы
min и max находят крайний элемент по Comparator.
reduce последовательно объединяет элементы в один результат.
int sum = Stream.of(3, 5, 7)
.reduce(0, Integer::sum);
Начальное значение здесь равно 0,
а каждый следующий элемент складывается с накопленным результатом.
Для сумм чисел позже увидим более прямые операции примитивных stream,
но reduce показывает общую идею свёртки.