It doesn't make sense to flatMap
a Stream that's already flat, like the Stream<Integer>
you've shown in your question.
However, if you had a Stream<List<Integer>>
then it would make sense and you could do this:
Stream<List<Integer>> integerListStream = Stream.of(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5)
);
Stream<Integer> integerStream = integerListStream .flatMap(Collection::stream);
integerStream.forEach(System.out::println);
Which would print:
1
2
3
4
5
To do this pre-Java 8 you just need a loops:
List<List<Integer>> integerLists = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5)
)
List<Integer> flattened = new ArrayList<>();
for (List<Integer> integerList : integerLists) {
flattened.addAll(integerList);
}
for (Integer i : flattened) {
System.out.println(i);
}
The lambda expression in flatMap
needs to return a Stream
, as can be seen by the argument of flatMap
which is of type Function<? super T, ? extends Stream<? extends R>>
.
The following code will compile and run fine:
listOfStrings.stream()
.flatMap(str -> duplicate(str).stream()) // note the .stream() here
.collect(Collectors.toList());
because the lambda expression str -> duplicate(str).stream()
is of type Function<String, Stream<String>>
.
Best Answer
Both
map
andflatMap
can be applied to aStream<T>
and they both return aStream<R>
. The difference is that themap
operation produces one output value for each input value, whereas theflatMap
operation produces an arbitrary number (zero or more) values for each input value.This is reflected in the arguments to each operation.
The
map
operation takes aFunction
, which is called for each value in the input stream and produces one result value, which is sent to the output stream.The
flatMap
operation takes a function that conceptually wants to consume one value and produce an arbitrary number of values. However, in Java, it's cumbersome for a method to return an arbitrary number of values, since methods can return only zero or one value. One could imagine an API where the mapper function forflatMap
takes a value and returns an array or aList
of values, which are then sent to the output. Given that this is the streams library, a particularly apt way to represent an arbitrary number of return values is for the mapper function itself to return a stream! The values from the stream returned by the mapper are drained from the stream and are passed to the output stream. The "clumps" of values returned by each call to the mapper function are not distinguished at all in the output stream, thus the output is said to have been "flattened."Typical use is for the mapper function of
flatMap
to returnStream.empty()
if it wants to send zero values, or something likeStream.of(a, b, c)
if it wants to return several values. But of course any stream can be returned.