In Java 8, what's the difference between Stream.map()
and Stream.flatMap()
methods?

- 124,154
- 35
- 280
- 359
-
72The type signature kinda tells the whole story. `map :: Stream T -> (T -> R) -> Stream R`, `flatMap :: Stream T -> (T -> Stream R) -> Stream R`. – Chris Martin Oct 31 '14 at 22:56
-
158fwiw, those type signatures don't even look like Java. (I know, I know -- but to say it tells "the whole story" wrt map/flatMap assumes a lot of knowledge about the new & improved "Java++") – michael Jul 17 '17 at 16:33
-
19@michael That type signature looks like Haskell, not Java. But it's not clear whether the actual Java signature is any more readable: `
Stream – Stuart Marks Jul 20 '17 at 01:34flatMap(Function super T,? extends Stream extends R>> mapper)`. -
17Ha, yeah, I was referring to the "actual Java". Like C++, modern Java is almost unrecognizable to anyone who started using it in the 90s (like I did, both languages). Just replying to the comment, that method signatures hardly tell a "whole story", at least not anymore, not without additional exposition (or in that commenters case, translation). – michael Jul 20 '17 at 13:19
-
5Which is to say, a `map`'s mapper lambda returns `R`, a `flatMap`'s mapper lambda returns a `Stream` of `R` (`Stream
`). The streams returned by the `flatMap`'s mapper are effectively concatenated. Otherwise, both `map` and `flatMap` return `Stream – derekm Mar 07 '18 at 19:20`; the difference is what the mapper lambdas return, `R` vs. `Stream `. -
2Use `map` if each element is transformed into a single value. Use `flatMap` if each element will be transformed to multiple values and the resulting stream needs to be flattened. – DimaSan Jun 11 '19 at 22:09
22 Answers
Both map
and flatMap
can be applied to a Stream<T>
and they both return a Stream<R>
. The difference is that the map
operation produces one output value for each input value, whereas the flatMap
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 a Function
, 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 for flatMap
takes a value and returns an array or a List
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 return Stream.empty()
if it wants to send zero values, or something like Stream.of(a, b, c)
if it wants to return several values. But of course any stream can be returned.

- 127,867
- 37
- 205
- 259
-
41Sounds to me like the `flatMap` operation is the exact opposite of flat. Yet again, leave it to Computer Scientists to turn a term on it's head. Like a function being "transparent" meaning you can't see anything it does, just the results, while colloquially saying you want a process to be transparent means you want every part of it to be seen. – coladict May 18 '17 at 07:53
-
59@coladict Try viewing it from a different perspective: it's not a transparent case where you can see the inner workings through, but the whole function itself is transparent, i.e. invisible, to you - while still doing their work and letting you see what you're working with. In this case, "flat" refers to the opposite of "nested", flatmap removes one nesting level by flattening. – Zefiro Jun 07 '17 at 16:10
-
13@coladict The "transparent" thing has been eating my head for years. Glad to know at least one other person feels the same way. – Ashok Bijoy Debnath Jul 19 '17 at 19:59
-
1@coladict: i was just thinking along the same line where does the flat part in the name come from? – markus Aug 02 '17 at 06:54
-
11Flattening comes from turning 2-level structure into single level structure, see Dici's answer for an example https://stackoverflow.com/a/26684582/6012102 – andrzej.szmukala Jan 16 '18 at 11:42
-
47This is the best explanation of **flatMap**. This is what makes it all clicked: *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"*. Thank you! – neevek Mar 07 '18 at 08:20
-
2@coladict @markus If you provided the same transformer method to `map` instead of `flatMap`, you would have a `Stream
>` instead of just a `Stream – bradynpoulsen Jun 27 '18 at 21:40` https://gist.github.com/bradynpoulsen/f3f5458d718a996c5b3dec9decefb6d2 -
-
@PålOliver Possibly. But people seem to like transparency, so the same word is used for two different meanings, depending on whether you're interested in seeing the inner mechanism (so the box around it is transparent for it to be seen) or don't want their view blocked by those details (so the whole mechanism is see-through). – Zefiro Oct 09 '20 at 23:13
-
-
Great answer, another typical usage would be using flatMap on an Optional, if the passed lambda returns an Optional too. – aderchox Sep 26 '21 at 23:54
-
Another advantage of using streams within the result: they can be lazily calculated, in case of large or expensive to compute streams. So if each item of the initial stream returns, say, a million records that are easily calculated, you don't need to have all million records in memory at once: the stream function can generate them as they are processed. – M. Justin Dec 24 '21 at 07:09
Stream.flatMap
, as it can be guessed by its name, is the combination of a map
and a flat
operation. That means that you first apply a function to your elements, and then flatten it. Stream.map
only applies a function to the stream without flattening the stream.
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 ]
.
-
10Haha, to be fair I'm still surprised to see how much traffic this question gets. Another funny observation is that it's been almost 5 years I wrote this answer and there's been a fairly consistent pattern of upvoting where the accepted answer gets roughly two upvotes for every one my answer gets. It's surprisingly consistent. – Dici Aug 24 '19 at 16:22
-
9how is this not the accepted answer, thank for getting straight to the point and putting a very simple example – 1mike12 Nov 04 '19 at 01:50
-
6I believe this answer is concise and logically better explained than the accepted one. – Morteza Aug 14 '20 at 14:56
-
3This answer is short and practical. The accepted (Stuart's) answer added an explanation on _why is that kind of method (`flatMap`) needed?_ Each answer cater for different types of answer that the community may seek. – aff Oct 26 '20 at 03:44
-
-
What is the use case of the flatMap? At the end I just want to collect it so I do not see why flatten it if at the end it will be a list or another collection, performance? map.collect vs flatMap.collect – BugsOverflow Mar 18 '23 at 02:55
-
If you collect it without flattening you'll get a list of lists (for example), which is not as easy to manipulate if all you care about are the values in the lists. If each list represents stronger concept like a cart of items or something like that, then keeping the items grouped in separate collections can make sense. – Dici Mar 19 '23 at 20:06
I would like to give 2 examples to get a more practical point of view:
First example making usage of map
:
@Test
public void convertStringToUpperCaseStreams() {
List<String> collected = Stream.of("a", "b", "hello") // Stream of String
.map(String::toUpperCase) // Returns a stream consisting of the results of applying the given function to the elements of this stream.
.collect(Collectors.toList());
assertEquals(asList("A", "B", "HELLO"), collected);
}
Nothing special in the first example, a Function
is applied to return the String
in uppercase.
Second example making usage of flatMap
:
@Test
public void testflatMap() throws Exception {
List<Integer> together = Stream.of(asList(1, 2), asList(3, 4)) // Stream of List<Integer>
.flatMap(List::stream)
.map(integer -> integer + 1)
.collect(Collectors.toList());
assertEquals(asList(2, 3, 4, 5), together);
}
In the second example, a Stream of List is passed. It is NOT a Stream of Integer!
If a transformation Function has to be used (through map), then first the Stream has to be flattened to something else (a Stream of Integer).
If flatMap
is removed then the following error is returned: The operator + is undefined for the argument type(s) List, int.
It is NOT possible to apply + 1 on a List
of Integers!

- 3,022
- 7
- 38
- 51

- 5,267
- 4
- 35
- 37
-
@PrashanthDebbadwar I think you would end up with a Stream of `Stream
` rather than a Stream of `Integer`. – payne Nov 27 '19 at 14:34
Please go through the post fully to get a clear idea,
map vs flatMap:
To return a length of each word from a list, we would do something like below..
Short Version given below
When we collect two lists, given below
Without flat map => [1,2],[1,1] => [[1,2],[1,1]] Here two lists are placed inside a list, so the output will be list containing lists
With flat map => [1,2],[1,1] => [1,2,1,1] Here two lists are flattened and only the values are placed in list, so the output will be list containing only elements
Basically it merges all the objects in to one
## Detailed Version has been given below:-
For example:-
Consider a list [“STACK”, ”OOOVVVER”] and we are trying to return a list like [“STACKOVER”](returning only unique letters from that list)
Initially, we would do something like below to return a list [“STACKOVER”] from [“STACK”, ”OOOVVVER”]
public class WordMap {
public static void main(String[] args) {
List<String> lst = Arrays.asList("STACK","OOOVER");
lst.stream().map(w->w.split("")).distinct().collect(Collectors.toList());
}
}
Here the issue is, Lambda passed to the map method returns a String array for each word, So the stream returned by the map method is actually of type Stream, But what we need is Stream to represent a stream of characters, below image illustrates the problem.
Figure A:
You might think that, We can resolve this problem using flatmap,
OK, let us see how to solve this by using map and Arrays.stream
First of all you gonna need a stream of characters instead of a stream of arrays. There is a method called Arrays.stream() that would take an array and produces a stream, for example:
String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
.map(Arrays::stream).distinct() //Make array in to separate stream
.collect(Collectors.toList());
The above still does not work, because we now end up with a list of streams (more precisely, Stream>), Instead, we must first convert each word into an array of individual letters and then make each array into a separate stream
By using flatMap we should be able to fix this problem as below:
String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
.flatMap(Arrays::stream).distinct() //flattens each generated stream in to a single stream
.collect(Collectors.toList());
flatMap would perform mapping each array not with stream but with the contents of that stream. All of the individual streams that would get generated while using map(Arrays::stream) get merged into a single stream. Figure B illustrates the effect of using the flatMap method. Compare it with what map does in figure A.
Figure B
The flatMap method lets you replace each value of a stream with another stream and then joins all the generated streams into a single stream.

- 179,855
- 19
- 132
- 245

- 3,039
- 1
- 24
- 30
-
4
-
1@TechDog I appreciate your example. I was stuck trying to find how to split up lines into words and stream them. – likejudo Jul 28 '20 at 19:29
-
2Thank you for your explanation based on practical examples with illustrations. It's very helpful for understanding. – invzbl3 Sep 22 '21 at 10:22
One line answer: flatMap
helps to flatten a Collection<Collection<T>>
into a Collection<T>
. In the same way, it will also flatten an Optional<Optional<T>>
into Optional<T>
.
As you can see, with map()
only:
- The intermediate type is
Stream<List<Item>>
- The return type is
List<List<Item>>
and with flatMap()
:
- The intermediate type is
Stream<Item>
- The return type is
List<Item>
This is the test result from the code used right below:
-------- Without flatMap() -------------------------------
collect() returns: [[Laptop, Phone], [Mouse, Keyboard]]
-------- With flatMap() ----------------------------------
collect() returns: [Laptop, Phone, Mouse, Keyboard]
Code used:
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class Parcel {
String name;
List<String> items;
public Parcel(String name, String... items) {
this.name = name;
this.items = Arrays.asList(items);
}
public List<String> getItems() {
return items;
}
public static void main(String[] args) {
Parcel amazon = new Parcel("amazon", "Laptop", "Phone");
Parcel ebay = new Parcel("ebay", "Mouse", "Keyboard");
List<Parcel> parcels = Arrays.asList(amazon, ebay);
System.out.println("-------- Without flatMap() ---------------------------");
List<List<String>> mapReturn = parcels.stream()
.map(Parcel::getItems)
.collect(Collectors.toList());
System.out.println("\t collect() returns: " + mapReturn);
System.out.println("\n-------- With flatMap() ------------------------------");
List<String> flatMapReturn = parcels.stream()
.map(Parcel::getItems)
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println("\t collect() returns: " + flatMapReturn);
}
}

- 13,452
- 11
- 45
- 44
-
14Very crisp example.., Wouldn't take more than few secs to understand the concept with your example... – TechDog Apr 05 '19 at 06:28
-
Thanks for mentioning that Optional
> to Optional – manikanta nvsr Apr 26 '21 at 10:01. Otherwise, it would've been answer by me!
.map is for A -> B
mapping
Stream.of("dog", "cat") // stream of 2 Strings
.map(s -> s.length()) // stream of 2 Integers: [3, 3]
it converts any item A
to any item B
. Javadoc
.flatMap is for A -> Stream< B>
concatinating
Stream.of("dog", "cat") // stream of 2 Strings
.flatMapToInt(s -> s.chars()) // stream of 6 ints: [d, o, g, c, a, t]
it --1 converts any item A
into Stream< B>
, then --2 concatenates all the streams into one (flat) stream. Javadoc
Note 1: Although the latter example flats to a stream of primitives (IntStream) instead of a stream of objects (Stream), it still illustrates the idea of the .flatMap
.
Note 2: Despite the name, String.chars() method returns ints. So the actual collection will be: [100, 111, 103, 99, 97, 116]
, where 100
is the code of 'd'
, 111
is the code of 'o'
etc. Again, for illustrative purposes, it's presented as [d, o, g, c, a, t].

- 9,236
- 1
- 55
- 38
The function you pass to stream.map
has to return one object. That means each object in the input stream results in exactly one object in the output stream.
The function you pass to stream.flatMap
returns a stream for each object. That means the function can return any number of objects for each input object (including none). The resulting streams are then concatenated to one output stream.

- 67,764
- 9
- 118
- 153
-
Why would you want to "return any number of objects for each input object (including none)"? – Derek Mahar Dec 12 '18 at 15:50
-
4@DerekMahar There would be plenty of use-cases for this. For example, let's say you have a stream of `Department`s in your organization. Each department has between 0 and n `Employee`s. What you need is a stream of all employees. So what do you do? You write a flatMap method which takes a department and returns a stream of its employees. – Philipp Dec 12 '18 at 16:11
-
Philipp, does your example illustrate the main reason to use `flatMap`? I suspect that it may be incidental and doesn't illustrate the key use case or reason why `flatMap` exists. (Continued below...) – Derek Mahar Dec 12 '18 at 17:17
-
After reading https://dzone.com/articles/understanding-flatmap, I think the main motivation behind `flatMap` is to accommodate errors that would be present when using `map`. How do you handle cases where one or more items in the original set cannot be mapped to an output item? By introducing an intermediate set (say an `Optional` or `Stream`) for each input object, `flatMap` allows you to exclude the "invalid" input objects (or the so called "bad apples" in the spirit of https://stackoverflow.com/a/52248643/107158) from the final set. – Derek Mahar Dec 12 '18 at 17:17
-
1@DerekMahar Yes, stuations where each input-object might or might not return an output-object is another good use-case for flat-map. – Philipp Dec 12 '18 at 17:21
for a Map we have a list of elements and a (function,action) f so :
[a,b,c] f(x) => [f(a),f(b),f(c)]
and for the flat map we have a list of elements list and we have a (function,action) f and we want the result to be flattened :
[[a,b],[c,d,e]] f(x) =>[f(a),f(b),f(c),f(d),f(e)]

- 2,484
- 1
- 24
- 26
I have a feeling that most answers here overcomplicate the simple problem. If you already understand how the map
works that should be fairly easy to grasp.
There are cases where we can end up with unwanted nested structures when using map()
, the flatMap()
method is designed to overcome this by avoiding wrapping.
Examples:
1
List<List<Integer>> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
.collect(Collectors.toList());
We can avoid having nested lists by using flatMap
:
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
.flatMap(i -> i.stream())
.collect(Collectors.toList());
2
Optional<Optional<String>> result = Optional.of(42)
.map(id -> findById(id));
Optional<String> result = Optional.of(42)
.flatMap(id -> findById(id));
where:
private Optional<String> findById(Integer id)

- 13,172
- 8
- 62
- 93
-
sorry but the 2nd snippet from point 1 is not compiling instead of `List
result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());` . It is should be `Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());` – arthur Mar 13 '18 at 18:16 -
@arthur I think I used Vavr's Stream and List here - but I agree that it might be confusing a bit - I will change that to standard Java – Grzegorz Piwowarek Mar 14 '18 at 07:07
-
@GrzegorzPiwowarek [how about this simple explanation](https://stackoverflow.com/a/52248643/1059372) ? – Eugene Sep 09 '18 at 21:06
map() and flatMap()
map()
Just takes a Function <T, R> a lambda param where T is element and R the return element built using T. At the end we'll have a Stream with objects of Type R. A simple example can be:
Stream
.of(1,2,3,4,5)
.map(myInt -> "preFix_"+myInt)
.forEach(System.out::println);
It simply takes elements 1 to 5 of Type Integer
, uses each element to build a new element from type String
with value "prefix_"+integer_value
and prints it out.
flatMap()
It is useful to know that flatMap() takes a function F<T, R>
where
T is a type from which a Stream can be built from/with. It can be a List (T.stream()), an array (Arrays.stream(someArray)), etc.. anything that from which a Stream can be with/or form. in the example below each dev has many languages, so dev. Languages is a List and will use a lambda parameter.
R is the resulting Stream that will be built using T. Knowing that we have many instances of T, we will naturally have many Streams from R. All these Streams from Type R will now be combined into one single 'flat' Stream from Type R.
Example
The examples of Bachiri Taoufiq [see its answer here] 1 are simple and easy to understanding. Just for clarity, let just say we have a team of developers:
dev_team = {dev_1,dev_2,dev_3}
, with each developer knowing many languages:
dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_3 = {lang_e,lang_f}
Applying Stream.map() on dev_team to get the languages of each dev:
dev_team.map(dev -> dev.getLanguages())
will give you this structure:
{
{lang_a,lang_b,lang_c},
{lang_d},
{lang_e,lang_f}
}
which is basically a List<List<Languages>> /Object[Languages[]]
. Not so very pretty, nor Java8-like!!
with Stream.flatMap()
you can 'flatten' things out as it takes the above structure
and turns it into {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, which can basically used as List<Languages>/Language[]/etc
...
so in the end, your code would make more sense like this:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.map(dev -> dev.getLanguages()) /* {{lang_a,...,lang_c},{lang_d}{lang_e,lang_f}}} */
.flatMap(languages -> languages.stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
or simply:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
When to use map() and use flatMap():
Use
map()
when each element of type T from your stream is supposed to be mapped/transformed to a single element of type R. The result is a mapping of type (1 start element -> 1 end element) and new stream of elements of type R is returned.Use
flatMap()
when each element of type T from your stream is supposed to mapped/transformed to a Collections of elements of type R. The result is a mapping of type (1 start element -> n end elements). These Collections are then merged (or flattened) to a new stream of elements of type R. This is useful for example to represent nested loops.
Pre Java 8:
List<Foo> myFoos = new ArrayList<Foo>();
for(Foo foo: myFoos){
for(Bar bar: foo.getMyBars()){
System.out.println(bar.getMyName());
}
}
Post Java 8
myFoos
.stream()
.flatMap(foo -> foo.getMyBars().stream())
.forEach(bar -> System.out.println(bar.getMyName()));

- 39,467
- 16
- 112
- 140

- 3,245
- 4
- 25
- 34
Oracle's article on Optional highlights this difference between map and flatmap:
String version = computer.map(Computer::getSoundcard)
.map(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
Unfortunately, this code doesn't compile. Why? The variable computer is of type
Optional<Computer>
, so it is perfectly correct to call the map method. However, getSoundcard() returns an object of type Optional. This means the result of the map operation is an object of typeOptional<Optional<Soundcard>>
. As a result, the call to getUSB() is invalid because the outermost Optional contains as its value another Optional, which of course doesn't support the getUSB() method.With streams, the flatMap method takes a function as an argument, which returns another stream. This function is applied to each element of a stream, which would result in a stream of streams. However, flatMap has the effect of replacing each generated stream by the contents of that stream. In other words, all the separate streams that are generated by the function get amalgamated or "flattened" into one single stream. What we want here is something similar, but we want to "flatten" a two-level Optional into one.
Optional also supports a flatMap method. Its purpose is to apply the transformation function on the value of an Optional (just like the map operation does) and then flatten the resulting two-level Optional into a single one.
So, to make our code correct, we need to rewrite it as follows using flatMap:
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
The first flatMap ensures that an
Optional<Soundcard>
is returned instead of anOptional<Optional<Soundcard>>
, and the second flatMap achieves the same purpose to return anOptional<USB>
. Note that the third call just needs to be a map() because getVersion() returns a String rather than an Optional object.
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

- 767
- 7
- 12
-
1the question was about Stream.map and Stream.flatMap & not about Optional.map anfd Optional.flatMap – djames Jun 13 '17 at 16:26
-
4But it helped me a lot to understand my problems with optional and flatmap, thanks a lot! – Loïc Jun 14 '17 at 06:58
-
2@djames, it's a perfectly valid answer, read it starting from paragraph "With streams, the flatMap method takes a function as an argument..." :) – skwisgaar Sep 19 '17 at 22:19
-
flatMap() version also throws nullpointerexception if soundCard is null. So where's the promised benefit of Optional? – Ekaterina Aug 23 '18 at 06:42
-
@Ekaterina, that's the pointer of working with `Optional`s, if the `getter`s return `Optional`s, then now `NullPointerException` will be thrown. – Mike Nov 23 '18 at 10:15
I am not very sure I am supposed to answer this, but every time I face someone that does not understand this, I use the same example.
Imagine you have an apple. A map
is transforming that apple to apple-juice
for example or a one-to-one mapping.
Take that same apple and get only the seeds out of it, that is what flatMap
does, or a one to many, one apple as input, many seeds as output.

- 117,005
- 15
- 201
- 306
-
For the `flatMap` case, do you first collect the seeds from each apple in separate bags, one bag per apple, before you pour all of the bags into a single bag? – Derek Mahar Dec 12 '18 at 16:04
-
@DerekMahar it used to be a poor into a single bag before java-10, meaning `flatmap` was not really lazy, but since java-10 it is lazy – Eugene Dec 12 '18 at 16:09
-
@Eugene please explain a little more lazy concept which you are trying to explain not clear to me.i understood what derkerMahar explained in comment is it that what happening before java10? – JAVA Apr 21 '19 at 13:52
-
-
@Eugene - The flatMap will take one apple at a time, extract its seeds and throw it into a bag/collection/array until all the apples seeds have been extracted. Right ? Is that how streams work ? – MasterJoe Mar 05 '20 at 05:22
-
-
@MasterJoe2 it seems like you have a specific question in mind, why not post it? – Eugene Mar 05 '20 at 11:07
-
@Eugene - I have posted it here https://stackoverflow.com/questions/60539486/is-my-understanding-of-java-stream-flatmap-correct – MasterJoe Mar 05 '20 at 18:44
-
1@Eugene I don't understand. seeds are different from juice. As I understand, flat map is supposed to reduce multiple streams to a single stream. I wonder if your analogy is incorrect. – likejudo Jul 28 '20 at 12:16
Map:- This method takes one Function as an argument and returns a new stream consisting of the results generated by applying the passed function to all the elements of the stream.
Let's imagine, I have a list of integer values ( 1,2,3,4,5 ) and one function interface whose logic is square of the passed integer. ( e -> e * e ).
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> newList = intList.stream().map( e -> e * e ).collect(Collectors.toList());
System.out.println(newList);
output:-
[1, 4, 9, 16, 25]
As you can see, an output is a new stream whose values are square of values of the input stream.
[1, 2, 3, 4, 5] -> apply e -> e * e -> [ 1*1, 2*2, 3*3, 4*4, 5*5 ] -> [1, 4, 9, 16, 25 ]
http://codedestine.com/java-8-stream-map-method/
FlatMap :- This method takes one Function as an argument, this function accepts one parameter T as an input argument and returns one stream of parameter R as a return value. When this function is applied to each element of this stream, it produces a stream of new values. All the elements of these new streams generated by each element are then copied to a new stream, which will be a return value of this method.
Let's image, I have a list of student objects, where each student can opt for multiple subjects.
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student("Robert","5st grade", Arrays.asList(new String[]{"history","math","geography"})));
studentList.add(new Student("Martin","8st grade", Arrays.asList(new String[]{"economics","biology"})));
studentList.add(new Student("Robert","9st grade", Arrays.asList(new String[]{"science","math"})));
Set<Student> courses = studentList.stream().flatMap( e -> e.getCourse().stream()).collect(Collectors.toSet());
System.out.println(courses);
output:-
[economics, biology, geography, science, history, math]
As you can see, an output is a new stream whose values are a collection of all the elements of the streams return by each element of the input stream.
[ S1 , S2 , S3 ] -> [ {"history","math","geography"}, {"economics","biology"}, {"science","math"} ] -> take unique subjects -> [economics, biology, geography, science, history, math]

- 496
- 5
- 11

- 459
- 5
- 6
-
could make a difference if you provide code instead of just provinding doc link – Charles-Antoine Fournel Feb 10 '17 at 11:03
-
you type is incorrect right? Set
courses = studentList.stream().flatMap( e -> e.getCourse().stream()).collect(Collectors.toSet()); should be a set of string here? – BabyishTank Aug 15 '22 at 20:22
By reading all the messages, the simple way to understand is :
- use
map
if you have aflat
list of elements: [0, 1, 2, 3, 4, 5] - use
flatMap
if you have a list of list of elements: [[1, 3, 5], [2, 4, 6]]. This means that, your list need to be flattened before the map operation can be applied to each elements

- 2,429
- 2
- 28
- 32
If you think map()
as an iteration(one level for
loop), flatmap()
is a two-level iteration(like a nested for
loop). (Enter each iterated element foo
, and do foo.getBarList()
and iterate in that barList
again)
map()
: take a stream, do something to every element, collect the single result of every process, output another stream. The definition of "do something function" is implicit. If the processment of any element results in null
, null
is used to compose the final stream. So, the number of elements in the resulting stream will be equal to number of input stream.
flatmap()
: take a stream of elements/streams and a function(explicit definition), apply the function to each element of each stream, and collect all the intermediate resulting stream to be a greater stream("flattening"). If the processment of any element results in null
, empty stream is provided to the final step of "flattening". The number of elements in the resulting stream, is the total of all participating elements in all inputs, if the input is several streams.

- 11,303
- 6
- 88
- 157
Simple answer.
The map
operation can produce a Stream
of Stream
.EX Stream<Stream<Integer>>
flatMap
operation will only produce Stream
of something. EX Stream<Integer>

- 3,847
- 10
- 44
- 81
Definitions of these Stream API methods:
map(Function mapper) is an intermediate operation which returns a stream consisting of the results of applying the given function to the elements of this stream.
flatMap(Function mapper) is an intermediate operation which returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. In short, it is used to convert a Stream of Stream into a list of values.
Take a look at example:
List<String> myList = Stream.of("Apple", "Orange")
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(myList);
It prints: [APPLE, ORANGE]
Can we just change map()
to flatMap()
?
List<String> myListFlat = Stream.of("Apple", "Orange")
.flatMap(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(myListFlat);
No, we can see an error now:
java: incompatible types: cannot infer type-variable(s) R
(argument mismatch; bad return type in method reference
java.lang.String cannot be converted to java.util.stream.Stream<? extends R>)
Why is that? Take a look at methods signatures:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
The reason why the code doesn’t work is that the flatMap()
method expects a function that returns a Stream. In second example, I am passing a method reference to String.toUpperCase()
which returns a String. Therefore, I am trying to apply flatMap()
on a Stream of characters instead of a Stream of Strings.
Ok, so now we can have an idea for what flatMap()
is used.
Let's build a list of lists:
List<List<String>> list = Arrays.asList(
Arrays.asList("Apple"),
Arrays.asList("Orange"));
System.out.println(list);
and it prints: [[Apple], [Orange]]
. If we want to have it flatten let's use flatMap()
:
List<String> flattedList = list
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(flattedList);
and now it prints: [Apple, Orange]
Sources: https://www.geeksforgeeks.org/stream-flatmap-java-examples/

- 5,058
- 7
- 47
- 80
This is very confusing for beginners. The basic difference is map
emits one item for each entry in the list and flatMap
is basically a map
+ flatten
operation. To be more clear, use flatMap when you require more than one value, eg when you are expecting a loop to return arrays, flatMap will be really helpful in this case.
I have written a blog about this, you can check it out here.

- 7,677
- 12
- 46
- 78
-
[how about this simple explanation](https://stackoverflow.com/a/52248643/1059372) ? – Eugene Sep 09 '18 at 21:06
Stream operations flatMap
and map
accept a function as input.
flatMap
expects the function to return a new stream for each element of the stream and returns a stream which combines all the elements of the streams returned by the function for each element. In other words, with flatMap
, for each element from the source, multiple elements will be created by the function. http://www.zoftino.com/java-stream-examples#flatmap-operation
map
expects the function to return a transformed value and returns a new stream containing the transformed elements. In other words, with map
, for each element from the source, one transformed element will be created by the function.
http://www.zoftino.com/java-stream-examples#map-operation
flatMap()
also takes advantage of partial lazy evaluation of streams. It will read the fist stream and only when required, will go to the next stream. The behaviour is explained in detail here: Is flatMap guaranteed to be lazy?

- 3,597
- 2
- 16
- 31
Also good analogy can be with C# if you familiar with. Basically C# Select
similar to java map
and C# SelectMany
java flatMap
. Same applies to Kotlin for collections.

- 4,972
- 4
- 26
- 39
map() takes a Stream and transform it to another Stream. It applies a function on each element of Stream and store return value into new Stream. It does not flatten the stream. But flatMap() is the combination of a map and a flat operation i.e, it applies a function to elements as well as flatten them. 2) map() is used for transformation only, but flatMap() is used for both transformation and flattening. please read more here. https://javaint4bytes.blogspot.com/2022/11/stream-flatmap-in-java-with-examples.html

- 11
- 2