explode (original) (raw)

Brian Goetz brian.goetz at oracle.com
Wed Feb 6 15:30:15 PST 2013


You said that we should not use Collection explicitly in the stream API hence we don't have toList(), toSet(), or groupBy() but collect(toList()), collect(toSet()) or collect(groupingBy) and at the same time, for flatMap which will be less used, you want to add flatMapToCollection, flatMapToArray.

Yes, any coupling to Collection is undesirable and has to be justified. We're currently in a nice place (zero uses of Collection in Stream) so it would be nice to stay there, and one is a lot worse than zero.

But be careful that you try to turn consistency into a goal unto itself. For example, the use of Collections in Collectors is an ideal compromise; the important thing is they are out of the core interface which we expect every aggregate for the next 10+ years to implement, but are still available for easy use through standalone static helper methods like groupingBy. This is an ideal balance of giving users tools to do their job without tying Stream to Collection.

I think you should be at least consistent, so either we have an Exploder like we have a Collector, or we have several overloads for flatMap, groupBy and toList/toSet.

Personally, I would (fairly strongly) prefer to have only:

Stream flatMap(FlatMapper<T, U>)

and

Stream flatMap(Function<T, Stream>)

One can quite easily derive the Collection (and with slightly more work, array) cases from the first form (or the second form, with more runtime overhead):

.flatMap((t, sink) -> getColl(t).forEach(sink)) .flatMap(t -> getColl(t).stream())

In fact, the first is what we originally had. But then people howled that (a) "I can't understand flatMap" and (b) "I think flatMap should take a Function<T, Collection>". In our early focus groups, people saw the base form of FlatMap and universally cried "WTF?" People can't understand it. After 100 people make the same comment, you start to get that its a pain point.

So, the proposal I made today attempts to take into account that people are not yet ready to understand this form of flatMap, and attempts to compromise. But I'll happily retreat from that, and vote for just

Stream flatMap(FlatMapper<T, U>) Stream flatMap(Function<T, Stream>)

It just seemed people weren't OK with that. (Though to be fair, we didn't always have the second form, and its addition might be enough to avoid the need for the Collection and array forms. It also allows reclaiming of the good name "flatMap", since there is actual mapping going on, and the generator form can piggyback on that.)

So, +1 to Remi's implicit suggestion:

Stream flatMap(FlatMapper<T, U>) Stream flatMap(Function<T, Stream>)

That's the new proposal.

Will be carved in stone in 24h unless there is further discussion :)



More information about the lambda-libs-spec-observers mailing list