4

I'm trying to understand flatMap: flatMap(x->stream.of(x) ) does not flat the stream and flatMap(x->x.stream()) works and gives the desired result. Can someone explain the difference between two?

import java.util.*;
import java.util.stream.*;

class TestFlatMap{

    public static void main(String args[]){
        List<String> l1 = Arrays.asList("a","b");
        List<String> l2 = Arrays.asList("c","d");

        Stream.of(l1, l2).flatMap((x)->Stream.of(x)).forEach((x)->System.out.println(x));

        Stream.of(l1, l2).flatMap((x)->x.stream()).forEach((x)->System.out.println(x));
    }

}

Output :

[a, b]
[c, d]
a
b
c
d
Eran
  • 387,369
  • 54
  • 702
  • 768
puvi
  • 231
  • 2
  • 10

2 Answers2

7

Stream.of(x) produces a Stream of a single element - x. Therefore, flatMap returns a Stream<List<String>> instead of Stream<String>.

On the other hand, x.stream() where x is a Collection<E> returns a Stream<E> whose source are the elements of the Collection, so in your case it returns a Stream<String>, which allows flatMap to produce a Stream<String> containing all the Strings in all the List<String>s of the source Stream.

You can see that in the Javadoc:

<T> Stream<T> java.util.stream.Stream.of(T t)
Returns a sequential Stream containing a single element.

vs.

Stream<E> stream()
Returns a sequential Stream with this collection as its source.

Eran
  • 387,369
  • 54
  • 702
  • 768
5

The thing you had in mind was this:

Stream.of(l1, l2)
      // String[]::new isn't really needed in this simple example,
      // but would be in a more complex one...
      .flatMap((x)->Stream.of(x.toArray(String[]::new)))
      .forEach((x)->System.out.println(x));

Which would also yield a flattened stream of a, b, c, d as you expected. Stream.of() comes in two flavours:

Since, when passing a List to Stream.of(), the only applicable overload is the one taking a single value, you got a Stream<List<String>> rather than the expected Stream<String>

Community
  • 1
  • 1
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509