Why can't Stream.flatMap accept a collection?
Asked Answered
P

1

11

Given the following as an example of data classes:

class Country {

    List<Region> regions = new ArrayList<>();

    List<Region> getRegions() {
        return regions;
    }

}

class Region {

    String getName() {
        return "some name";
    }

}

Presuming I would have a List of Countries

    List<Country> countries = new ArrayList<>();

And I wanted to Stream those to their Regions and their corresponding names I would like to do the following:

    countries.stream().flatMap(Country::getRegions).map(Region::getName)...

However that code does not compile since the return value of "getRegions" is a Collection (List) as opposed to a Stream, which the flatMap Method accepts. But since I know that any Collection can be streamed via its Collection.stream() Method that shouldn't be a problem. Still I am forced to write it as follows:

    countries.stream().flatMap(c -> c.getRegions().stream()).map(Region::getName)...

Which is (given a richer context) far less readable than the former.

Questions is, is there any reason, that I am missing out on, for this to be that bulky? I have plenty of examples in our framework at which I am forced to take that route, always leaving me with a sour taste. (Guess I just have to add Kotlin to our projects and extend the Stream class with a flatMap Method that takes a Collection :p or do I?)

Paperback answered 9/2, 2017 at 16:52 Comment(6)
I also tried the following as it made sense in my head, obviously it did not compile: Country::getRegions::streamPaperback
I agree that flatMap should accept a collection, but I'm not sure SO is going to be able to provide a definitive explanation, other than "the people that wrote it didn't write it that way".Illomened
"no" could also be an answer :)Paperback
Please, check if Collectors.groupingBy helps you. Some examples available at: mkyong.com/java8/…Conflict
You could return a Stream<Country> from the method instead. Or add a method regions that does that.Merete
You can still do .map(Country::getRegions).flatMap(List::stream), but I don’t get why method references are considered so superior to a simple lambda expression…Slangy
G
18

A technical reason, which is not ideal but could be why this wasn't done. You can't overload on a generic type in Java.

They need to support

 Stream.flatMap(Function<Object, Stream<X>> function)

which means they can't overload it with

 Stream.flatMap(Function<Object, Collection<X>> function)

as these two methods have the same signature after erasure.

They could add a method

 Stream.flatMapCollection(Function<Object, Collection<X>> function)

or

 Stream.flatMapIterable(Function<Object, Iterable<X>> function)

 Stream.flatMapI(Function<Object, Iterable<X>> function)

but it wouldn't be pretty.

Gerry answered 9/2, 2017 at 16:56 Comment(4)
Yes, if those methods were added it would be an improvement.Illomened
@Illomened it might not be any shorter. Ideally they would add support for rarefied types and overloading on generics.Gerry
That answer is actually satisfying. Or rather it provides a valid explanation. ThanksPaperback
flatCollection and flatArray are provided in StreamEx.Disturbed

© 2022 - 2024 — McMap. All rights reserved.