Что такое Stream API в Java
Что проверяют
Понимаете ли вы ленивость и то, что поток не хранит данные и не изменяет источник.
Как отвечать
Stream API это способ описать обработку последовательности декларативно: что сделать, а не как обойти. Поток не хранит элементы и не изменяет источник, он описывает конвейер.
Конвейер состоит из трёх частей:
- источник: коллекция, массив,
Stream.of,Files.lines, генератор; - промежуточные операции, возвращающие поток:
filter,map,flatMap,sorted,distinct,limit,skip,peek. Все ленивые: до терминальной операции ничего не выполняется; - терминальная операция, запускающая обработку:
collect,forEach,reduce,count,anyMatch,findFirst,toList.
Ленивость даёт два следствия. Первое: элементы проходят конвейер по одному до конца, а не по стадиям целиком, поэтому нет промежуточных коллекций. Второе: короткозамкнутые операции вроде findFirst и anyMatch останавливают обработку, не доходя до конца источника.
Поток одноразовый: после терминальной операции повторное использование даёт IllegalStateException.
Сбор результата через Collectors: toList, toMap, groupingBy, partitioningBy, joining, summingInt. С Java 16 есть короткий stream.toList(), возвращающий неизменяемый список.
Для чисел есть IntStream, LongStream, DoubleStream, избавляющие от упаковки и дающие sum, average, range.
Про parallelStream скажите с оговоркой: он использует общий пул ForkJoinPool.commonPool, поэтому оправдан только для вычислительной работы на больших объёмах и категорически не подходит для блокирующих операций ввода-вывода, потому что займёт общий пул на всё приложение.
Где спотыкаются
Изменяют внешнее состояние внутри forEach или map, ломая ленивость и параллельность.
Используют peek для побочных эффектов и удивляются, что он не вызвался.
Ставят parallelStream везде «для скорости».
Не знают, что поток нельзя переиспользовать.