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?)
We can use a flatMap() method on a stream with the mapper function List::stream. On executing the stream terminal operation, each element of flatMap() provides a separate stream. In the final phase, the flatMap() method transforms all the streams into a new stream.
The flatMap() method first flattens the input Stream of Streams to a Stream of Strings (for more about flattening, see this article).
Both of the functions map() and flatMap are used for transformation and mapping operations. map() function produces one output for one input value, whereas flatMap() function produces an arbitrary no of values as output (ie zero or more than zero) for each input value. Where R is the element type of the new stream.
Does flatmap() method preserve the order of the streams? Yes, It does and map() also.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With