J.J. Beam
J.J. Beam

Reputation: 3059

Why flatMap doesn't flat Stream<Stream<SomeClass>> to the SomeClass but rather to Stream<SomeClass>?

What I read about flatMap:

To understand what flattening a stream consists in, consider a structure like [ [1,2,3],[4,5,6],[7,8,9] ] which has "two levels". Flattening this means transforming it in a "one level" structure : [ 1,2,3,4,5,6,7,8,9 ]

import java.util.List;
import java.util.stream.Stream;

public class FlatMapDemo {
    List<Country> countries;
    void demoFlatMap(){
        Stream<Stream<City>> streamStreamCity = countries
                .stream()
                .map(country -> country.cities.stream());
        streamStreamCity.flatMap(cityStream -> /*it's not City, it's Stream<City> !!!*/);
    }
}
class Country{
    List<City> cities;
}
class City {
    int population;
}

So I just wanna count all population from all countries but in cities which has > 1000 inhabitants. So I created Stream<Stream<City>> and hope flatMap flat for me Stream<Stream and give me City class to take something like: .flatMap(city -> city.population) to filter after: .filter(population > 1000) but it seems I was wrong. Please explain why flatMap doesn't do this? Isn't it the purpose of flattening?

Upvotes: 0

Views: 200

Answers (1)

Didier L
Didier L

Reputation: 20618

The goal of flatMap() is not to apply a transformation on the A items of a Stream<Stream<A>>. If you end up with such a type it most likely indicates you misused a map() operation somewhere.

The goal of flatMap() is instead to transform a Stream<A> into a Stream<B> when you have a function f that can produce a Stream<B> from individual A elements (simplifying a bit, it is a Function<A, Stream<B>>). I.e. it “flattens” the stream by avoiding to end up with nested streams.

You would use it like

getStreamOfA().flatMap(f) // returns Stream<B>

So in your example:

Stream<City> cityStream = countries
                .stream()
                .flatMap(country -> country.cities.stream());

Upvotes: 1

Related Questions