Stream API

Тема дорожной карты · Java

Java Stream API — это мощная абстракция функционального программирования, введённая в Java 8, обеспечивающая декларативную, ленивую и опционально параллельную обработку последовательностей данных из Collections, массивов, I/O-каналов или функций-генераторов без мутации источника. Конвейер Stream<T> состоит из источника, нуля или более промежуточных операций — filter(Predicate), map(Function), flatMap(Function), sorted(Comparator), distinct(), limit(n), peek(Consumer) — и терминальной операции — collect(Collector), forEach(Consumer), reduce(BinaryOperator), count(), findFirst(), anyMatch(Predicate), — запускающей ленивое вычисление всего конвейера. Java Stream API предоставляет специализированные примитивные потоки — IntStream, LongStream, DoubleStream — для обработки примитивных типов Java без накладных расходов на автоупаковку, и фабричные методы CollectorsgroupingBy, partitioningBy, joining, toMap, teeing — для сложной агрегации. Параллельные потоки через stream().parallel() или Collection.parallelStream() распределяют вычисления по общему ForkJoinPool, обеспечивая почти линейное ускорение для CPU-ёмких, без сохранения состояния, невмешивающихся операций над большими наборами данных, хотя необходимо тщательно учитывать потокобезопасность и семантику упорядочивания. Java Stream API является идиоматической основой современных Java-функций и беспрепятственно интегрируется с Lambda-выражениями, ссылками на методы, Optional, Generics и фреймворками вроде Spring Data JPA с потоковыми результатами Stream<T> и ScrollableResults Hibernate.

Как это работает

Stream API покрывает generics (параметры типа: class Box<T>, List<String>, Map<K, V>), wildcards (? extends, ? super, правило PECS), функциональные интерфейсы (один abstract-метод: Function, Consumer, Supplier, Predicate), лямбды (x -> x.toUpperCase()), method references (String::toUpperCase), Stream API. Type erasure означает, что generic-инфа исчезает на рантайме — работает на compile-time, но List<String>.class тот же, что List<Integer>.class.

Когда применять

Stream API — для трансформаций (.filter().map().collect()) когда intent яснее цикла. Generics — в API библиотек чтобы протолкнуть type-safety вызывающим. Применяйте PECS (Producer Extends, Consumer Super) при проектировании wildcards. Не over-engineer — Function<? super T, ? extends R> иногда правильный ответ, иногда запах.

Типичные ошибки

Ловушки Stream API: List rawList = new ArrayList() (raw-типы — обходят generics, ломают type-safety); злоупотребление Stream .peek() для side-эффектов (это для дебага — forEach если нужны side-эффекты); stateful-лямбды (parallel streams + mutable shared state = race); instanceof + cast вместо pattern matching (Java 21+).

Связанные понятия

Полезные ресурсы