История вопроса:
Stream API было добавлено в Java 8 для облегчения функционального программирования и параллельной обработки коллекций. Оно предоставляет удобный способ описывать цепочки операций над данными через лямбда-выражения.
Проблема:
Без Stream API приходилось писать громоздкий императивный код для фильтрации, сортировки и агрегации коллекций. Потенциал для ошибок, сложность сопровождения, неэффективность при попытке добавить параллелизм вручную.
Решение:
Stream API позволяет построить pipeline из промежуточных (intermediate) и терминальных (terminal) операций. Потоки ленивы, работают с данными последовательно или параллельно, код становится компактнее и выразительнее.
Пример обработки коллекции:
List<String> names = Arrays.asList("Анна", "Иван", "Петр", "Ева"); names.stream() .filter(s -> s.length() > 3) .map(String::toUpperCase) .sorted() .forEach(System.out::println);
Ключевые особенности:
parallelStream()), но нужно учитывать thread-safety коллекций и функцийМожно ли переиспользовать один и тот же Stream после его закрытия?
Нет, попытка повторного использования закрытого Stream выбрасывает IllegalStateException. Поток одноразовый.
Влияет ли изменение исходной коллекции после создания Stream?
Да, если коллекция изменена после создания Stream, но до терминальной операции, возможны ConcurrentModificationException.
Можно ли использовать внешние изменяемые переменные внутри Stream-операций?
Не рекомендуется, так как в параллельном стриме это приводит к неожиданным ошибкам. Лучше избегать мутабельных side-effect в Stream-пайплайне.
.parallelStream() к коллекциям, не являющимся потокобезопаснымиПрограммист вызывает через Stream некоторый метод, который меняет внешний список — это срабатывает при последовательном выполнении, но при параллельном даёт расстройство структуры данных.
Плюсы:
Минусы:
Весь пайплайн строится чисто: операции не имеют сайд-эффектов, используются только неизменяемые коллекции, финальный результат собирается через collector.
Плюсы:
Минусы: