<div dir="ltr">Hi Viktor!<br><br>Thanks for your insights, those are really valuable. I went through the usages around the codebase and actually found out that any pipeline using this gatherers actually ended up with either toList or collect(Collectors.toUnmodifiableSet()), that is probably why I have never noticed something off around short circuiting, though implementations are clearly are not designed right in this terms. Thank you for the correction!<br><br>Best regards</div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Oct 20, 2025 at 11:22 AM Viktor Klang <<a href="mailto:viktor.klang@oracle.com">viktor.klang@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="msg7124061275802637279">




<div dir="ltr">
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
Thank you for sharing your practical experience with Gatherers, Olexandr—it is much appreciated!</div>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
Some thoguhts while reading your email:</div>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<ul style="margin-top:0px;margin-bottom:0px;list-style-type:disc">
<li style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<div role="presentation">Given that your custom Gatherers shown never short-circuit, you might find it performance-wise valuable to instantiate then with Gatherer.Integrator.ofGreedy.</div>
</li></ul>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<ul style="margin-top:0px;margin-bottom:0px;list-style-type:disc">
<li style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<div role="presentation">For your finishers, I've personally found it valuable to short-circuit of the downstream push returns false, so in the cases above it'd be something like</div>
</li></ul>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
        If (!downstream.push(element))<br>
            return;</div>
<div id="m_7124061275802637279Signature">
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
Cheers,<br>
√</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<b><br>
</b></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<b>Viktor Klang</b></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
Software Architect, Java Platform Group<br>
Oracle</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div style="text-align:left;margin-left:5pt;font-family:Calibri;font-size:10pt;color:rgb(0,0,0)">
Confidential – Oracle Internal</div>
</div>
<div id="m_7124061275802637279appendonsend"></div>
<hr style="display:inline-block;width:98%">
<div id="m_7124061275802637279divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> core-libs-dev <<a href="mailto:core-libs-dev-retn@openjdk.org" target="_blank">core-libs-dev-retn@openjdk.org</a>> on behalf of Olexandr Rotan <<a href="mailto:rotanolexandr842@gmail.com" target="_blank">rotanolexandr842@gmail.com</a>><br>
<b>Sent:</b> Friday, 17 October 2025 20:45<br>
<b>To:</b> core-libs-dev <<a href="mailto:core-libs-dev@openjdk.org" target="_blank">core-libs-dev@openjdk.org</a>><br>
<b>Subject:</b> My expirience with gatherers</font>
<div> </div>
</div>
<div>
<div dir="ltr">Greetings to the core libs folks. I have been using Gatherers extensively for my job in a past few months, and would like to share some of the gatherers that I have been extensively using, so maybe some of them may be a source of inspiration
 for evolving the Gatherers class.<br>
<br>
1. eagerlyConsume()<br>
Implementation:
<div>
<div style="background-color:rgb(30,31,34);color:rgb(188,190,196)">
<pre style="font-family:"JetBrains Mono",monospace"><span style="color:rgb(207,142,109)">public static </span><<span style="color:rgb(22,186,172)">T</span>> Gatherer<<span style="color:rgb(22,186,172)">T</span>, ?, <span style="color:rgb(22,186,172)">T</span>> <span style="color:rgb(86,168,245)">eagerlyConsume</span>() {<br>    <span style="color:rgb(207,142,109)">return </span>Gatherer.<span style="font-style:italic">of</span>(<br>        ArrayList<<span style="color:rgb(22,186,172)">T</span>>::<span style="color:rgb(207,142,109)">new</span>,<br>        (list, val, downstream) -> {<br>            list.add(val);<br>            <span style="color:rgb(207,142,109)">return true</span>;<br>        },<br>        (left, right) -> {<br>            left.addAll(right);<br>            <span style="color:rgb(207,142,109)">return </span>left;<br>        },<br>        (list, downstream) -> {<br>            <span style="color:rgb(207,142,109)">for </span>(<span style="color:rgb(207,142,109)">var </span>item : list) {<br>                downstream.push(item);<br>            }<br>        }<br>    );<br>}</pre>
</div>
</div>
<div>Purpose: many times, i need to perform a concurrent mapping of jpa entities to dtos. Unfortunately, mapConcurrent does not accept custom executors, which i need in order to propagate auth, transaction and other contexts. So, therefore, I previously have
 used following pattern:<br>
<br>
stream().map(COmpletableFuture.supplyAsync(..., executor)).toList().stream().map(CompletableFuture::join)<br>
<br>
toList is required here to eagerly start all futures, as otherwise the will actually launch sequentially due to the pulling nature of streams. With gatherer, on the other hand, i can achieve following:<br>
stream().map(COmpletableFuture.supplyAsync(..., executor))..gather<font color="#000000" face="arial, sans-serif">(eagerlyConsume())</font> .map(CompletableFuture::join), which looks much more readable, and (presumably, haven't actually verified it) should have
 better performance<br>
<br>
2. ofCollector<br>
Implementation:<br>
<div style="background-color:rgb(30,31,34);color:rgb(188,190,196)">
<pre style="font-family:"JetBrains Mono",monospace"><span style="color:rgb(207,142,109)">public </span><<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">R</span>> Gatherer<<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">R</span>> <span style="color:rgb(86,168,245)">ofCollector</span>(Collector<<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">R</span>> collector) {<br>    <span style="color:rgb(207,142,109)">return </span>Gatherer.<span style="font-style:italic">of</span>(<br>        collector.supplier(),<br>        (a, t, _) -> {<br>            <span style="color:rgb(199,125,187)">collector</span>.accumulator().accept(a, t);<br>            <span style="color:rgb(207,142,109)">return true</span>;<br>        },<br>        collector.combiner(),<br>        (state, downstream) -> downstream.push(<span style="color:rgb(199,125,187)">collector</span>.finisher().apply(state))<br>    );<br>}</pre>
</div>
Pretty self explanatory, this is just an adapter of collector to gatherer, allowing arbitrary collector-defined folds<br>
<br>
3. collectThenFlatten & co<br>
Implementations:<br>
</div>
<div>
<div style="background-color:rgb(30,31,34);color:rgb(188,190,196)">
<pre style="font-family:"JetBrains Mono",monospace"><span style="color:rgb(207,142,109)">public static </span><<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">R </span><span style="color:rgb(207,142,109)">extends </span>Collection<<span style="color:rgb(22,186,172)">T</span>>> Gatherer<<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">T</span>> <span style="color:rgb(86,168,245)">collectThenFlatten</span>(Collector<<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">R</span>> collector) {<br>    <span style="color:rgb(207,142,109)">return </span>Gatherer.<span style="font-style:italic">of</span>(<br>        collector.supplier(),<br>        (a, t, _) -> {<br>            <span style="color:rgb(199,125,187)">collector</span>.accumulator().accept(a, t);<br>            <span style="color:rgb(207,142,109)">return true</span>;<br>        },<br>        collector.combiner(),<br>        (state, downstream) -> {<br>            <span style="color:rgb(207,142,109)">for </span>(<span style="color:rgb(207,142,109)">var </span>item : <span style="color:rgb(199,125,187)">collector</span>.finisher().apply(state)) {<br>                downstream.push(item);<br>            }<br>        }<br>    );<br>}<br><br><span style="color:rgb(207,142,109)">public static </span><<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">K</span>, <span style="color:rgb(22,186,172)">V</span>, <span style="color:rgb(22,186,172)">R </span><span style="color:rgb(207,142,109)">extends </span>Map<<span style="color:rgb(22,186,172)">K</span>, <span style="color:rgb(22,186,172)">V</span>>> Gatherer<<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, Map.Entry<<span style="color:rgb(22,186,172)">K</span>, <span style="color:rgb(22,186,172)">V</span>>> <span style="color:rgb(86,168,245)">collectThenFlattenEntries</span>(Collector<<span style="color:rgb(22,186,172)">T</span>, <span style="color:rgb(22,186,172)">A</span>, <span style="color:rgb(22,186,172)">R</span>> collector) {<br>    <span style="color:rgb(207,142,109)">return </span>Gatherer.<span style="font-style:italic">of</span>(<br>        collector.supplier(),<br>        (a, t, _) -> {<br>            <span style="color:rgb(199,125,187)">collector</span>.accumulator().accept(a, t);<br>            <span style="color:rgb(207,142,109)">return true</span>;<br>        },<br>        collector.combiner(),<br>        (state, downstream) -> {<br>            <span style="color:rgb(207,142,109)">for </span>(<span style="color:rgb(207,142,109)">var </span>entry : <span style="color:rgb(199,125,187)">collector</span>.finisher().apply(state).entrySet()) {<br>                downstream.push(entry);<br>            }<br>        }<br>    );<br>}</pre>
</div>
</div>
<div>These are more specialized adapters of collector adapters, mostly a convenience for avoiding flatMapping results, THough, I would like to note that <font face="arial, sans-serif" color="#000000">collectThenFlattenEntries is mostly used specifically
 with groupingBy collector, to avoid following nasty chains:<br>
<br>
collect(groupingBy(...)).entrySet().stream()<br>
<br>
Maybe it's just my personal preferences, but i really dislike this back n forth from stream to map, then to set and to stream again, so this gatherer seems pretty pleasant to use<br>
<br>
That's basically all that I wanted to share regarding this topic, hope this experience will have some value for core libs maintainers<br>
<br>
Best regards</font></div>
</div>
</div>
</div>

</div></blockquote></div>