RFR: JDK-8319123 : Implementation of JEP-461: Stream Gatherers (Preview) [v2]

Viktor Klang vklang at openjdk.org
Thu Nov 9 10:09:08 UTC 2023


On Wed, 8 Nov 2023 17:11:39 GMT, Rémi Forax <forax at openjdk.org> wrote:

>> The API should be client-friendly, not implementor-friendly, given that it's expected to have much more clients than implementors. An implementor can easily delegate to a private method to add missing type parameters. I did exactly this in the [teeing](https://github.com/openjdk/jdk/blob/7d25f1c6cb770e21cfad8096c1637a24e65fab8c/src/java.base/share/classes/java/util/stream/Collectors.java#L1913) Collector before. There should not be a reason to expose a parameter, which is merely an implementation detail. This also complicates the public documentation of the already complex feature, specifying the parameter which is not necessary to specify. 
>> 
>>> Has this proven to be a problem for things like [Collectors.mapping(…)](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Collectors.html#mapping(java.util.function.Function,java.util.stream.Collector)) ?
>> 
>> I'm not sure how I can prove this, given that you don't usually know the downstream accumulator, so if somebody hits this problem, they will be forced to solve it in another way (e.g., extracting parts of complex collector to separate variables), so you won't find the code in the wild which uses `mapping` type arguments explicitly. Yes, `Collectors.mapping` and `groupingBy` did this mistake in the past, and there's no reason to repeat it again.
>> 
>>> Do you have a concrete example of where the current "encoding" causes a caller-problem?
>> 
>> For example, I want to create a reusable gatherer that performs scan-concat and wraps every resulting string with '[...]'. First try:
>> 
>> 
>> var gatherer = Gatherers.scan(() -> "", String::concat)
>>   .andThen(Gatherer.ofSequential((_, t, pusher) -> pusher.push(STR."[{t}]")));
>> 
>> 
>> Now, the type of `gatherer` is `Gatherer<String, ?, Object>`, but I want `Gatherer<String, ?, String>`. I have the following alternatives:
>> 1. Specify the variable type explicitly:
>> 
>> Gatherer<String, ?, String> gatherer = Gatherers.scan(() -> "", String::concat)
>>     .andThen(Gatherer.ofSequential((_, t, pusher) -> pusher.push(STR."[{t}]")));
>> 
>> 2. Specify `ofSequential` type arguments:
>> 
>> var gatherer = Gatherers.scan(() -> "", String::concat)
>>     .andThen(Gatherer.<String, String>ofSequential((_, t, pusher) -> pusher.push(STR."[{t}]")));
>> 
>> 3. Specify the types of lambda arguments explicitly:
>> 
>> var gatherer = Gatherers.scan(() -> "", String::concat)
>>     .andThen(Gatherer.ofSequential((Void _, String t, Downstream<? super String> pusher) ->...
>
> I agree with Tagir here, it should be an ? and if you want to capture it in a type variable you can use the standard trick of having the private method declaring the type variable and the public method with the wildcard calling the private method.

Sold! Type argument removed!

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/16420#discussion_r1387774512


More information about the core-libs-dev mailing list