Какой тип данных возвращает list.stream().map(...) в Java
Что проверяют
Понимаете ли вы, что стрим это конвейер, а не коллекция. Вопрос про возвращаемый тип простой, но он вход в разговор о ленивости: следом спрашивают, что выполнится, если после map не вызвать терминальную операцию, и почему исходный список не изменился.
Как отвечать
Ответ по существу: map возвращает Stream<R>, где R это тип результата переданной функции Function<T, R>. Исходный список не меняется, новая коллекция не создаётся.
- ленивость:
mapэто промежуточная операция. Пока не вызвана терминальная (collect,toList,forEach,reduce,count), лямбда не выполнится ни разу; - порядок обхода: элементы идут по конвейеру по одному, а не слоями. Если перед
mapстоитfilter, функция применится только к прошедшим фильтр, аfindFirstможет оборвать обход раньше конца; - примитивы:
mapToInt,mapToLongиmapToDoubleвозвращаютIntStream,LongStreamиDoubleStreamи убирают упаковку. Обратно в объектный стрим переводитboxed(); - сбор результата:
collect(Collectors.toList())даёт изменяемый список,toList()из Java 16 сразу отдаёт неизменяемый, при этомnullвнутри допускает, в отличие отCollectors.toUnmodifiableList(); - вложенность: если функция сама возвращает стрим или коллекцию, нужен
flatMap, иначе получитеStream<Stream<R>>.
Стоит добавить, что стрим одноразовый: повторное обращение к уже использованному даёт IllegalStateException.
Где спотыкаются
Отвечают «список». Stream не коллекция: у него нет ни размера, ни доступа по индексу, и он ничего не хранит.
Пишут list.stream().map(...) ради побочного эффекта и удивляются, что ничего не произошло. Без терминальной операции конвейер не запускается, да и map для побочных эффектов не предназначен.
Не замечают упаковки: map(String::length) даёт Stream<Integer> с боксингом каждого значения, тогда как mapToInt работает с примитивами.