<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
<br>
<div data-ogsc=""></div>
<blockquote style="border-color: rgb(200, 200, 200); border-left: 3px solid rgb(200, 200, 200); padding-left: 1ex; margin-left: 0.8ex;" itemscope="" itemtype="https://schemas.microsoft.com/QuotedText">
<div data-ogsc="">I will ask for a step further and add an overload to collect that takes a Gatherer and calls gather(gatherer).collect(Collectors.singleton()) so we can directly write<br>
</div>
<div data-ogsc=""> var neatlyFolded = stream.collect(fold(...));<br>
</div>
<div data-ogsc=""><br>
</div>
<div data-ogsc="">As a user, I see value in using the more powerful Gatherer API like a collector without having to think too much.</div>
</blockquote>
</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
<br>
</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
While I can definitely sympathize with this idea, very few Gatherers emit strictly a single element under all executions, and I'd expect that users will not always want that enforced by default (throwing an exception when number of elements not being strictly
1).</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);" class="elementToProof">
<br>
</div>
<div class="elementToProof">
<div id="Signature">
<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<br>
</div>
</div>
</div>
</div>
<div id="appendonsend"></div>
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> Remi Forax <forax@univ-mlv.fr><br>
<b>Sent:</b> Monday, 30 October 2023 23:39<br>
<b>To:</b> Viktor Klang <viktor.klang@oracle.com><br>
<b>Cc:</b> Tyler Kindy <me@tylerkindy.com>; core-libs-dev <core-libs-dev@openjdk.org><br>
<b>Subject:</b> Re: [External] : Re: Update on JEP-461: Stream Gatherers (Preview)</font>
<div> </div>
</div>
<div>
<div style="font-family:arial,helvetica,sans-serif; font-size:12pt; color:#000000">
<div><br>
</div>
<div><br>
</div>
<hr id="x_zwchr" data-marker="__DIVIDER__">
<div data-marker="__HEADERS__">
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<b>From: </b>"Viktor Klang" <viktor.klang@oracle.com><br>
<b>To: </b>"Tyler Kindy" <me@tylerkindy.com><br>
<b>Cc: </b>"core-libs-dev" <core-libs-dev@openjdk.org><br>
<b>Sent: </b>Monday, October 30, 2023 10:59:48 PM<br>
<b>Subject: </b>Re: [External] : Re: Update on JEP-461: Stream Gatherers (Preview)<br>
</blockquote>
</div>
<div><style style="display:none">
<!--
p
{margin-top:0;
margin-bottom:0}
-->
</style></div>
<div data-marker="__QUOTED_TEXT__">
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<div class="x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
That's also a good point, and I've heard from multiple sources that sometimes you want to make sure that you only have a single element left at the end, and otherwise throw an exception.</div>
</blockquote>
<div><br>
</div>
<div>Hello,<br data-mce-bogus="1">
</div>
<div><br data-mce-bogus="1">
</div>
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<div class="x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Fortunately it is possible to do something to the effect of:</div>
<div class="x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
// Proof of concept only<br>
</div>
<div class="x_elementToProof x_ContentPasted0" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
public static <T> Collector<T,?,T> singleton() {
<div class="x_ContentPasted0"> class State { T value; boolean hasValue; }</div>
<div class="x_ContentPasted0"> return Collector.of(</div>
<div class="x_ContentPasted0"> State::new,</div>
<div class="x_ContentPasted0"> (state, e) -> {</div>
<div class="x_ContentPasted0"> if (state.hasValue)</div>
<div class="x_ContentPasted0"> throw new IllegalStateException("Stream has more than one element!");</div>
<div><br class="x_ContentPasted0">
</div>
<div class="x_ContentPasted0"> state.hasValue = true;</div>
<div class="x_ContentPasted0"> state.value = e;</div>
<div class="x_ContentPasted0"> },</div>
<div class="x_ContentPasted0"> (left, right) -> {</div>
<div class="x_ContentPasted0"> if (left.hasValue && right.hasValue)</div>
<div class="x_ContentPasted0"> throw new IllegalStateException("Stream has more than one element!");</div>
<div class="x_ContentPasted0"> else if (left.hasValue)</div>
<div class="x_ContentPasted0"> return left;</div>
<div class="x_ContentPasted0"> else</div>
<div class="x_ContentPasted0"> return right;</div>
<div class="x_ContentPasted0"> },</div>
<div class="x_ContentPasted0"> (state) -> {</div>
<div class="x_ContentPasted0"> if (!state.hasValue)</div>
<div class="x_ContentPasted0"> throw new IllegalStateException("Stream has less than one element!");</div>
<div class="x_ContentPasted0"> else</div>
<div class="x_ContentPasted0"> return state.value;</div>
<div class="x_ContentPasted0"> });</div>
}</div>
<div class="x_elementToProof x_ContentPasted0" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_elementToProof x_ContentPasted0" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Which means that you could write things like:<br>
<br>
var neatlyFolded = stream.gather(fold(…)).collect(singleton());</div>
</blockquote>
<div><br>
</div>
<div>I will ask for a step further and add an overload to collect that takes a Gatherer and calls gather(gatherer).collect(Collectors.singleton()) so we can directly write<br data-mce-bogus="1">
</div>
<div> var neatlyFolded = stream.collect(fold(...));<br data-mce-bogus="1">
</div>
<div><br data-mce-bogus="1">
</div>
<div>As a user, I see value in using the more powerful Gatherer API like a collector without having to think too much.</div>
<div><br data-mce-bogus="1">
</div>
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<div class="x_elementToProof x_ContentPasted0" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_elementToProof">
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div id="x_Signature">
<div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Cheers,<br>
√</div>
</div>
</div>
</div>
</blockquote>
<div><br>
</div>
<div>regards,<br data-mce-bogus="1">
</div>
<div>Rémi<br data-mce-bogus="1">
</div>
<div><br data-mce-bogus="1">
</div>
<blockquote style="border-left:2px solid #1010FF; margin-left:5px; padding-left:5px; color:#000; font-weight:normal; font-style:normal; text-decoration:none; font-family:Helvetica,Arial,sans-serif; font-size:12pt">
<div class="x_elementToProof">
<div id="x_Signature">
<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<br>
</div>
</div>
</div>
</div>
<hr style="display:inline-block; width:98%">
<div id="x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> Tyler Kindy <me@tylerkindy.com><br>
<b>Sent:</b> Monday, 30 October 2023 18:38<br>
<b>To:</b> Viktor Klang <viktor.klang@oracle.com><br>
<b>Cc:</b> core-libs-dev@openjdk.org <core-libs-dev@openjdk.org><br>
<b>Subject:</b> Re: [External] : Re: Update on JEP-461: Stream Gatherers (Preview)</font>
<div> </div>
</div>
<div dir="auto">
<div dir="ltr">Hi Viktor,</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">Thanks for the response! I see what you mean, it’s a good point that single-element streams are just as valid as streams with other numbers of elements.</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">The weird part for me, though, is getting the folded result out of the stream at the end (which, while not always, I believe will be the most common thing to want to do after `fold`). The obvious way, which you used in your presentation, is `findAny`.
Since the stream could be empty, it makes sense that `findAny` returns an `Optional`, but with `fold` we know that the stream will have exactly one element in it.</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">Of course, this API is totally serviceable. You can use `Optional::orElseThrow` on the result of `findAny` to communicate your intent that you expect there to be an element. But that feels a bit roundabout to me; I feel that a cleaner API would
be to get the folded result out directly, like how `Collector` works.</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">To your point, implementing `fold` as a Gatherer doesn’t mean we can never have a terminal `fold`. And having `fold` in any way at all is great; that’s one feature of Streams I commonly find myself wanting when writing code (the other is windowing,
which I think you’ve covered the need for well; no notes on those \uD83D\uDE04).</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">But it does make me wish that `Collector` was also flexible enough to implement `fold`. Maybe a topic for future work. \uD83D\uDE04</div>
<div dir="ltr"><br>
</div>
<div dir="ltr">Thanks again,</div>
<div dir="ltr">Tyler</div>
<div dir="ltr"><br>
<blockquote>On Oct 30, 2023, at 10:39 AM, Viktor Klang <viktor.klang@oracle.com> wrote:<br>
<br>
</blockquote>
</div>
<blockquote>
<div dir="ltr">
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Hi Tyler,</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
Thank you for the kind words -- they are much appreciated. And you have a very good question indeed!<br>
</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
My thinking behind making <i>fold</i> a Gatherer is that I think that it is strictly more powerful than "only" having it as a collector (It wouldn't be able to be a Collector since you'd need a combiner for it, but also being able to compose it with other operations,
choosing the output type at a later stage in the process, and so forth).<br>
</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
Also, if you think about it -- single-element Streams are just as valid as empty Streams, N-sized Streams, or even unbounded Streams, and conceptually, there's no difference between the following two Streams:</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<div class="x_x_elementToProof" style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
var a = Stream.of("1234")<br>
var b = Stream.of(1,2,3,4).gather(fold(() -> "", (str, next) -> str + next))</div>
<div class="x_x_elementToProof">
<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)">
So that was my thinking—allow developers to stay within Stream processing for as long as they want, and choose the terminal operation when they need to break out from the Stream.</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)">
<br>
</div>
<div id="x_x_Signature">
<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<br>
</div>
</div>
</div>
</div>
<hr style="display:inline-block; width:98%">
<div id="x_x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> Tyler Kindy <me@tylerkindy.com><br>
<b>Sent:</b> Monday, 30 October 2023 12:14<br>
<b>To:</b> Viktor Klang <viktor.klang@oracle.com><br>
<b>Cc:</b> core-libs-dev@openjdk.org <core-libs-dev@openjdk.org><br>
<b>Subject:</b> [External] : Re: Update on JEP-461: Stream Gatherers (Preview)</font>
<div> </div>
</div>
<div dir="auto">
<div dir="ltr">
<div dir="ltr">Thanks for the JEP and your talk, Viktor! I think `Stream::gather` will be super useful in my day-to-day as a Java developer.
<div><br>
</div>
<div>I’m curious why `<font face=".AppleSystemUIFont">fold`</font> is being implemented with gatherers. I recognize `Gatherer` is designed to support intermediate operations, but `fold` feels inherently like a terminal operation to me since it, like `reduce`
or `collect`, consumes all the elements in the stream and produces a single result.</div>
<div><br>
</div>
<div>Is there a technical limitation to making `fold` a terminal operation? For example, does `Collector` inherently presume parallelization in a way that `Gatherer` does not?</div>
<div><br>
</div>
<div>Or is the idea mainly to demonstrate the power of gatherers, and we could also make `fold` a terminal operation with the current `Stream` API?</div>
<div><br>
</div>
<div>Thank you!</div>
<div>Tyler Kindy<br id="x_x_x_lineBreakAtBeginningOfMessage">
<div class="x_x_x_AppleOriginalContents" style="direction:ltr"><br>
<blockquote>
<div>On Oct 27, 2023, at 9:50 AM, Viktor Klang <viktor.klang@oracle.com> wrote:</div>
<br class="x_x_x_Apple-interchange-newline">
<div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
Greetings,</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<br>
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
As you may have already seen,<b>Stream Gatherers</b>is now a<a href="https://openjdk.org/jeps/461" title="https://openjdk.org/jeps/461" id="LPlnk995248" class="x_x_x_OWAAutoLink" target="_blank">Preview JEP with Candidate status</a><br data-mce-bogus="1">
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<br>
</div>
<div class="x_x_x_elementToProof x_x_x_ContentPasted0" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
Work-in-progress (interfaces, implementation, tests, benches, and documentation) for JEP-461 is currently available<a href="https://urldefense.com/v3/__https://github.com/viktorklang-ora/jdk/tree/gatherer__;!!ACWV5N9M2RV99hQ!Lz2sC02xW35XpuwoaqBvD_iR80Xrzkbj-60oOKuQklUOm8e69-O3WC9N93leBFbMkFmULJmsat9k1dmt$" title="https://github.com/viktorklang-ora/jdk/tree/gatherer" id="OWA8ab01dac-cb46-bda0-009f-d3a4a0a6e81e" class="x_x_x_OWAAutoLink x_x_x_ContentPasted0" target="_blank">here</a>.<br>
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<br>
</div>
<div class="x_x_x_elementToProof x_x_x_ContentPasted2" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
While<a href="https://cr.openjdk.org/~vklang/Gatherers.html" title="https://cr.openjdk.org/~vklang/Gatherers.html " id="LPlnk332869" class="x_x_x_OWAAutoLink" target="_blank">the design</a>has held up well, there are some important improvements made since the
original design document was written.<br>
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<br>
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
Notable changes (without any particular order):</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<ul>
<li style="list-style-type:disc"><b>Stream::gather()</b>now has a default implementation.<br>
<br>
</li><li style="list-style-type:disc"><b><span>Gatherer</span>::supplier()</b>was renamed to<b>Gatherer::initializer()</b>to better reflect intent.<br>
<br>
</li><li style="list-style-type:disc"><b>Gatherer.Sink<R></b>was renamed to<b>Gatherer.Downstream<R></b>to better signal what it represents.<br>
<br>
</li><li style="list-style-type:disc"><b>Gatherer::collect(Collector)</b>and its companion type<b>Gatherer.ThenCollector</b>was dropped due to compatibility concerns with existing code which operates on<b>Collector</b>.<br>
<br>
</li><li style="list-style-type:disc">
<div><span><b>Gatherer.Characteristics</b>have been eliminated and superseded by having default values that are used as sentinels.<br>
</span></div>
(discussed further down the list)<br>
<div><span>This is important because with the Characteristics-model keeping alignment between Characteristics and actual implementation proved brittle, and under composition of Gatherers computing the union was inefficient and mostly lead to an empty set in
the end.<br>
<br>
</span></div>
</li><li style="list-style-type:disc"><span><b>Gatherer.defaultInitializer()</b>,<b>Gatherer.defaultCombiner()</b>, and<b>Gatherer.defaultFinisher()</b>were added as static methods—these are the sentinels used to elide calling the initializer, to elide calling the
combiner (avoid parallelization), and to elide calling the finisher, respectively.<br>
<br>
</span></li><li style="list-style-type:disc"><span><b>Gatherer::initializer()</b>,<b>Gatherer::combiner()</b>, and<b>Gatherer::finisher()</b>default implementations return the respective sentinels.<br>
<br>
</span></li><li style="list-style-type:disc"><span>A subtype of<b>Integrator</b>named<b>Greedy</b>was added, together with a factory method to guide lambda-to-nominal-type conversion. This allows creators of Gatherers to signal that an<b>Integrator</b>will never initiate
a short-circuit (but may relay one from downstream), and that is available during evaluation to determine if the operation can short-circuit or not.</span>
<div style="list-style-type:disc"><br>
</div>
</li><li style="list-style-type:disc"><span>Factories for creating anonymous Gatherers were expanded upon to include<b>Gatherer.of()</b>and<b>Gatherer.ofSequential()</b>with different sets of parameters, primarily to make it more ergonomical and easier to read and
write the code using those factories.</span>
<div style="list-style-type:disc"><br>
</div>
</li><li style="list-style-type:disc"><span>A curated set of initial built-in Gatherers is located in<b>java.util.stream.Gatherers</b><br>
</span></li></ul>
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
</div>
<div class="x_x_x_elementToProof x_x_x_ContentPasted1" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
I recently presented<a href="https://urldefense.com/v3/__https://www.youtube.com/watch?v=8fMFa6OqlY8__;!!ACWV5N9M2RV99hQ!Lz2sC02xW35XpuwoaqBvD_iR80Xrzkbj-60oOKuQklUOm8e69-O3WC9N93leBFbMkFmULJmsam2MP-_S$" title="https://www.youtube.com/watch?v=8fMFa6OqlY8" id="LPlnkOWALinkPreview_2" class="x_x_x_OWAAutoLink" target="_blank">Gatherers
at Devoxx</a>, which I'd recommend watching for an introduction to the feature.<br>
</div>
<div class="x_x_x__Entity x_x_x__EType_OWALinkPreview x_x_x__EId_OWALinkPreview_8 x_x_x__EReadonly_1" style="font-family:Helvetica; font-size:12px; font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none">
<div id="LPBorder_BVTaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g:dj04Zk1GYTZPcWxZOA.." class="x_x_x_LPBorder874039" style="width:777px; margin-top:16px; margin-bottom:16px; max-width:800px; min-width:424px">
<table id="LPContainer874039" style="padding:12px 36px 12px 12px; width:777px; border-width:1px; border-style:solid; border-color:rgb(200,200,200); border-radius:2px">
<tbody>
<tr valign="top" style="border-spacing:0px">
<td>
<div id="LPImageContainer874039" style="margin-right:12px; height:180px; overflow:hidden; width:240px">
<a target="_blank" id="LPImageAnchor874039" href="https://urldefense.com/v3/__https://www.youtube.com/watch?v=8fMFa6OqlY8__;!!ACWV5N9M2RV99hQ!Lz2sC02xW35XpuwoaqBvD_iR80Xrzkbj-60oOKuQklUOm8e69-O3WC9N93leBFbMkFmULJmsam2MP-_S$"><span class="x_x_x_AppleTemporaryEditingElement" id="x_x_x_cid:d048f613-b144-4ff9-a2d3-98e0765aab57"><Outlook-cztoycvq.jpg></span></a><br data-mce-bogus="1">
</div>
</td>
<td style="width:465px">
<div id="LPTitle874039" style="font-size:21px; font-weight:300; margin-right:8px; font-family:wf_segoe-ui_light,"Segoe UI Light","Segoe WP Light","Segoe UI","Segoe WP",Tahoma,Arial,sans-serif; margin-bottom:12px">
<a target="_blank" id="LPUrlAnchor874039" href="https://urldefense.com/v3/__https://www.youtube.com/watch?v=8fMFa6OqlY8__;!!ACWV5N9M2RV99hQ!Lz2sC02xW35XpuwoaqBvD_iR80Xrzkbj-60oOKuQklUOm8e69-O3WC9N93leBFbMkFmULJmsam2MP-_S$" style="text-decoration:none">Teaching
old Streams new tricks By Viktor Klang</a><br data-mce-bogus="1">
</div>
<div id="LPDescription874039" style="font-size:14px; max-height:100px; font-family:wf_segoe-ui_normal,"Segoe UI","Segoe WP",Tahoma,Arial,sans-serif; margin-bottom:12px; margin-right:8px; overflow:hidden; color:rgb(102,102,102)">
Have you ever wanted to perform an operation on a java.util.stream.Stream only to find that the existing set of operations didn't provide what you needed—forcing you to break out early from the Stream and perform the logic outside of it? As a matter of fact,
java.util.stream was the first JDK API designed with lambdas in mind and was ...</div>
<div id="LPMetadata874039" style="font-size:14px; font-weight:400; font-family:wf_segoe-ui_normal,"Segoe UI","Segoe WP",Tahoma,Arial,sans-serif; color:rgb(166,166,166)">
<a href="https://urldefense.com/v3/__http://www.youtube.com/__;!!ACWV5N9M2RV99hQ!Lz2sC02xW35XpuwoaqBvD_iR80Xrzkbj-60oOKuQklUOm8e69-O3WC9N93leBFbMkFmULJmsalMQI96j$" target="_blank">www.youtube.com</a><br data-mce-bogus="1">
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="x_x_x_elementToProof" style="font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none; font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<br>
</div>
<div class="x_x_x_elementToProof" style="font-family:Helvetica; font-size:12px; font-style:normal; font-variant-caps:normal; font-weight:400; letter-spacing:normal; text-align:start; text-indent:0px; text-transform:none; white-space:normal; word-spacing:0px; text-decoration:none">
<div style="font-family:Aptos,Aptos_EmbeddedFont,Aptos_MSFontService,Calibri,Helvetica,sans-serif; font-size:12pt">
<br>
</div>
<div id="x_x_x_Signature">
<div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt">Cheers,<br>
√</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt"><br>
</div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt"><b><br>
</b></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt"><b>Viktor Klang</b></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt">Software Architect, Java Platform Group<br>
Oracle</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
<br>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
<br>
</blockquote>
</div>
</div>
</div>
</body>
</html>