Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Stream Gatherers - Write Your Own Stream Opera...

Stream Gatherers - Write Your Own Stream Operations!

The Java Stream API was introduced with Java 8 in March 2014, providing us with an indispensable tool for data processing.

However, the limited set of intermediate operations – `filter`, `map`, `flatMap`, `mapMulti`, `distinct`, `sorted`, `peak`, `limit`, `skip`, `takeWhile`, and `dropWhile` – means that more complex data transformations cannot be expressed directly through the Stream API.

Operations like window and fold, among many others, are missing if we look at the community's feature requests.

Instead of integrating all these operations into the Stream interface, the JDK team developed a new API that, on the one hand, is used within the JDK itself to provide highly requested intermediate operations and, on the other hand, allows developers to implement their own operations.

This new API is called "Stream Gatherers" and was first released as a preview feature (JEP 461) in Java 22 in March 2024, exactly ten years after the introduction of the Stream API. In Java 23, the new API was sent into a second preview round without changes (JEP 473), and in Java 24, it was finalized – again without changes (JEP 485).

In this talk, you will learn in theory and practice (including live coding) what Stream Gatherers are and how they work, which Gatherers are already available in the JDK and how to use them effectively, how to implement your own Gatherers, and where the limits of the new API lie.

Avatar for Sven Woltmann

Sven Woltmann

March 31, 2025
Tweet

More Decks by Sven Woltmann

Other Decks in Programming

Transcript

  1. Copyright © 2025, HappyCoders.eu Stream Pipeline Source Intermediate operations stream()

    Terminal operation toList() filter(…) limit(…) map(…)
  2. Copyright © 2025, HappyCoders.eu List<String> fruits = List.of("avocado", "banana", "cantaloupe",

    "dragon fruit", "fig", "grapefruit", "honeydew", "jujube", "kiwi", "lime", "mango", "pineapple", "raspberry", "star fruit", "tomato", "watermelon"); List<String> result = fruits.stream() .filter(fruit -> fruit.length() >= 8) .limit(3) .toList();
  3. Copyright © 2025, HappyCoders.eu avocado banana cantaloupe dragon fruit fig

    grapefruit honeydew jujube kiwi lime mango pineapple raspberry star fruit tomato watermelon avocado banana cantaloupe dragon fruit fig grapefruit cantaloupe dragon fruit grapefruit ✘ ✘ ✔ ✔ ✘ ✔ cantaloupe dragon fruit grapefruit ✔ ✔ ✔ cantaloupe dragon fruit stream() toList() filter(…) limit(…) 3 grapefruit “STOP!” ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘ ✘
  4. Copyright © 2025, HappyCoders.eu window!!! fold!!! map(...) flatMap(...) filter(...) limit(...)

    mapMulti(...) distinct() sorted() skip(...) takeWhile(...) dropWhile(...) peek(...) Intermediate Operations in the JDK
  5. Copyright © 2025, HappyCoders.eu Demo the two of and a

    be in that the be two of and a in that
  6. Copyright © 2025, HappyCoders.eu windowFixed(int windowSize) windowSliding(int windowSize) fold(Supplier<R> initial,

    BiFunction<? super R, ? super T, ? extends R> folder) scan(Supplier<R> initial, BiFunction<? super R, ? super T, ? extends R> scanner) mapConcurrent(int maxConcurrency, Function<? super T, ? extends R> mapper) Predefined Stream Gatherers
  7. Copyright © 2025, HappyCoders.eu • No access to the characteristics

    of the stream, no indication of which characteristics are retained. • No gatherers for the primitive streams IntStream, LongStream, and DoubleStream Performance + Limits
  8. Copyright © 2025, HappyCoders.eu int[] array = IntStream.iterate(1, i ->

    i + 1) .filter(i -> i % 7 == 0) .limit(3) .toArray();
  9. Copyright © 2025, HappyCoders.eu List<String> words = . . .

    Faster! long count = words.stream() .map(String::toUpperCase) .count(); long count = words.stream() .gather(mapping(String::toUpperCase)) .count(); 3.7 µs 861,529.6 µs