Win a copy of The Way of the Web Tester: A Beginner's Guide to Automating Tests this week in the Testing forum!

# Streams and "top level"? (Study Guide: flatMap())

Dóra Takács
Ranch Hand
Posts: 33
4
Hellow! :3

I have been studying for my OCP, and got a bit lost in the study guide. In the part explaining about streams and the flatMap() function, there is a sentence saying the following:
(chapter 4, page 198) As you can see, it removed the empty list completely and changed all elements of each list to be at the top level of the stream.

Code:

Output:
Bonobo
Mama Gorilla
Baby Gorilla

Can someone please elaborate on what does this "top level" thing mean?

As I have tried to understand, I ended up with something like, we have a stream here taking Lists, and this stream with the flatMap() would be able to make a new List (like a top level list, that could act like a steam itself) with all the lists and their elements, except for the empty ones, in this example.
Is this correct? I'm not sure about it.

Thank you in advance!

Campbell Ritchie
Sheriff
Posts: 50749
83
• 1
I can't think of an example at the moment, but I can probably find a copy of a book like Urma Fusco and Mycroft Java 8 in Action (Manning) (page 98).
They show the example of trying to convert an array of words
["Dóra", "Takács"]
to an array of 1‑character words.
["D", "ó", "r", "a", "T", "a", "k", "á", "c", "s"]But, they say, the Stream in line 3 is not a String<String> which is what you want, but a Stream<String[]>. You will end up with a List<String[]> and the compiler will complain. They say to use flatMap to sort out the problem, flattening the arrays into indiviudal Strings, which would often not make sense outside Streams.#A: converts each word into an array of its individual letters
#B: flatten each generated stream into one single stream

The term flatten means to convert the contents of data structures into one data structure; it is traditionally applied to sets:-
You can also flatten Lists of Lists into a single List, arrays of arrays into a single array, etc., but as I said “flatten” was usually applied to sets, converting a set of sets into a single “flat” set.

I shall duplicate this discussion in our Java8 forum.

Campbell Ritchie
Sheriff
Posts: 50749
83
• 1
I have never heard the term top level applied to streams. I presume it means that the elements the Stream iterates are not packaged in anything else.

Dóra Takács
Ranch Hand
Posts: 33
4
I presume it means that the elements the Stream iterates are not packaged in anything else.

This actually makes a lot of sense, thank you!
And the example was really helpful. I've been playing around with streams and couldn't figure out why my practices hadn't compiled, until you wrote the exact thing I was trying to make work....

So, one last thing. In the previous example, if I had

It would mean the flatMap() would flatten it the way you explained, thus resulting in the exact same output, and "Mama Gorilla" would be added once only, because sets must stay unique?

Campbell Ritchie
Sheriff
Posts: 50749
83
• 1
Dóra Takács wrote:. . . "Mama Gorilla" would be added once only, because sets must stay unique?
You do not appear to have any sets in the code you wrote. Unless you use something like
.distinct()
in line 6½, you are dealing with a Stream<List<Animal>> and the Mama Gorilla would appear twice because it is in two Lists. If however you use something like
.collect(Collectors.toSet())
then you will create a Set and Mama Gorilla will only appear once.

If you don't flatten your forEach call will print
[]
[Bonobo, Mama Gorilla]
[Mama Gorilla, Baby Gorilla]
… because you have the three Lists. If you flatten the Streams you will get
Bonobo
Mama Gorilla
Mama Gorilla
Baby Gorilla
… and converting it to a set will give
{Bonobo, Mama Gorilla, Baby Gorilla}
I suggest you put a peek call somewhere in your code.
animals.peek(l -> System.out.println(l))
animals.flatMap(...).peek(l -> System.out.println(l))
Remember you will get no output until you write something “downstream” of that to make the Streams run and “consume” their inputs.
Another suggestion: run the code on Eclipse. Hover your mouse over each method call, and a tooltip will appear with the type of the expression in. It will read something like Stream<Animal> or Stream<List<Animal>>, and you can follow the different types of Stream through the execution.

Style thing: Separate your Stream code so each method call is on its own line and the . operators line up vertically. It will make hovering the mouse on Eclipse easier, too.
You will have to think of an argument to pass to my flatMap calls. List::stream or Arrays::stream as Urma Fusco and Mycroft suggested might work.

Dóra Takács
Ranch Hand
Posts: 33
4
Thank you very much, Mr Ritchie! :3
I currently dont have access to a JDK, that's why I'm asking stuff like "would it print out..." instead of actually trying it. I will have the chance to experiment a lot with it tomorrow, though.
I asked the question because I felt really vague and uncomfortable with the topic, but I feel a lot more like "back on the track of understanding" now!

I really appreciate the time you put in to help me!
Someone please give the man a cow!

Best regards, Dóri

Liutauras Vilda
Bartender
Posts: 2544
91
• 1
Dóra Takács wrote:I really appreciate the time you put in to help me!
Someone please give the man a cow!
Indeed his answers were very helpful and lots of community members will benefit from that. Thank you for appreciating Sheriffs work

Campbell Ritchie
Sheriff
Posts: 50749
83
• 1
That's a pleasure and thank you for the cow, Liutauras or whoever gave it