From the course: Java 25 for Professionals with Jetbrains AI Assistant
Stream gatherers in action: Writing custom data collectors - Java Tutorial
From the course: Java 25 for Professionals with Jetbrains AI Assistant
Stream gatherers in action: Writing custom data collectors
- [Instructor] What is even cooler is that we can create our own custom gatherer. Let's say we want to drop consecutive duplicate values. Here's how to go about it. You build one with gatherer of and then you pass in the initializer, integrator, finisher, and combiner. Just to be clear, what we want is that a sequence like this, b, a, a, b, b, c turns into b, a, b, c. So the Bs are duplicates. They can stay. Only consecutive duplicates will have to be removed. If we choose distinct, all the duplicates would be gone, not only when they are consecutive, and that's why we need a custom solution. And you can see it here. On line nine I'm creating a state which is my private per pipeline state. And then here's the magic. Here, I'm creating a custom gatherer, so I am passing in a new state. Then we get the integrator, which is code for each upstream element. And because of the off (indistinct), the integrator never short circuits early. Then on line 20, we emit the element, and by returning through, we continue to process. And the finisher is saying that we don't want to emit extra at the end. And then here we're testing it. So as you can see, I'm passing in the values and then I'm saying .gather. And I'm passing in the static distinctUntilChanged, which is returning a gatherer. And then I'm printing the outputs. And as you can see, it's giving us the expected results. So a getherer is built from three main parts, a state, integrator, and finisher. The state keeps track of the previous elements, so we can compare with the current one and has previous checks if we have seen at least one element yet. And previous knows the last emitted element. Every stream pipeline gets its own state object, one per run of the pipeline. And then we have the integrator. We compare the current element to the last one. If it's different, we push it downstream, which means we emit it. If it's the same, we skip it and always return through means that it keeps going and that there's no short circuiting here. And again, (indistinct) means process everything and don't stop early. And then we have to finish here. It runs at the end of the stream. Here, we don't need to flush any leftover state, so it's empty. And that's how to create your own gatherer. Of course, obviously when you have more complex use cases, it'll lead to more complex codes, but the main principles, still stay the same.