This JEP Café explains what Gatherers are, as a new addition to the Java 8 Stream API, introduced in the JDK 24. It goes through all you need to know to use this API efficiently, in a step-by-step approach, with many examples, from the simplest you can imagine, to more complex ones. It gives you in-depth details of the intermediate and terminal operations of the Stream API, and how they work internally, to better understand how Gatherers are working, and why this API has been designed in that way. You will learn about using flat-mapping to validate the elements of your stream, how you can use mapMulti() to avoid creating stream objects, how some stream operations have to manage an internal mutable state to work, how they can interrupt a stream, and how parallelization works under the hood. All this can be used in the creation of your custom gatherers.
You can watch all the episodes on the JEP Café series here: https://www.youtube.com/playlist?list=PLX8CzqL3ArzV4BpOzLanxd4bZr46x5e87
00:00 Introduction
01:09 Introducing the Stream API
01:49 Connecting a Stream to a source of data
04:05 Calling method on a Stream
05:16 Making the difference intermediate and terminal operations
06:43 Triggering the computation with a terminal operation
08:29 Producing elements with an intermadiate operation
09:45 Validating elements with flatMap() and mapMulti()
14:02 Terminating a stream with an intermediate operation
15:18 Delaying the start of a computation with an internal mutable state
16:44 Bufferzing stream elements in an intermadiate operation
18:54 Methods you should only use for debugging
20:49 Characteristics of a Stream
22:02 Using forEach() for debugging
22:54 Reducing a stream with count(), min(), max(), sum(), or average()
24:26 Short-circuiting a stream with terminal operations
25:31 Reducing a stream in a mutable container with a collector
28:10 Creating your own Collector from a supplier, and an accumulator
31:14 Adding a finisher to a Collector to create non modifiable containers
32:43 Using collectors outside of the Stream API
34:00 Going parallel with Streams
37:15 Using parallel streams with SIZED and SUBSIZED sources
39:52 Sharing mutable state in parallel streams
41:44 Reducing parallel streams with associative reductions
42:43 Choosing to use parallel streams
43:41 Modeling intermediate stream operations with Gatherers
45:26 Writing a mapping Gatherer
49:08 Writing an interrupting Gatherer holding an internal mutable state
51:55 Managing the stream interruption with your integrator
54:29 Optimizing a Gatherer with a greedy integrator
55:11 Writing a sliding window Gatherer
57:43 Writing a correct windowing Gatherer with a finisher
01:01:04 Implementing a parallel Gatherer with a combiner
01:07:20 Adding the combiner to enable parallel gathering
01:10:33 Using non-parallel Gatherers in parallel Streams
01:12:04 Wrapping up Gatherers
01:13:09 That's it for today, talk to you soon!
⎯⎯⎯⎯⎯⎯ Resources ⎯⎯⎯⎯⎯⎯
◦ The JEP 485 about Gatherers ➱ https://openjdk.org/jeps/485
◦ The JEP 454 about the Foreign Function and Memory API ➱ https://openjdk.org/jeps/454
◦ Nicolai on Gatherers ➱ https://youtu.be/epgJm2dZTSg and https://youtu.be/pNQ5OXMXDbY
◦ Dev.java ➱ https://dev.java
◦ Inside.java ➱ https://inside.java
◦ JDK 24 ➱ https://openjdk.org/projects/jdk/24
◦ JDK 23 ➱ https://openjdk.org/projects/jdk/23
◦ OpenJDK ➱ https://openjdk.org
◦ Oracle Java ➱ https://www.oracle.com/java/