Java 8 Streams FlatMap method example
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);
}
What's the difference between map() and flatMap() methods in Java 8?
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.
flatMap triple nested streams
You can do this in two steps:
first create concatenation of countries and titles list:
List<String> countriesTitle = countries.stream()
.flatMap(country -> titles.stream()
.map(title -> country + "_" + title))
.collect(Collectors.toList());
then by previous result create list of concatenation country+"_"+title+"_"+game
string:
Stream.concat(games.stream(),
games.stream()
.flatMap(game -> countriesTitle.stream()
.map(countryTitle -> countryTitle + "_" + game)))
.collect(Collectors.toList());
Updated answer:
games.stream()
.flatMap(game -> countries.stream()
.flatMap(country -> titles.stream()
.flatMap(title -> Stream.of(game, country + "_" + title + "_" + game))))
.collect(Collectors.toSet());
Java 8: Flattening StreamStream
flatMap( i -> i)
will essentially concatenate the streams.
Usage of flatMap() in Java8
Your external loop counts the number of members that have the band coming from Kolkata
. if you actually want that:
long result = artists.stream().filter(a -> a.getOrigin().equals("Kolkata"))
.filter(a -> a.getMembers() != null)
.flatMap(a -> a.getMembers())
.count();
Using Java 8's Optional with Stream::flatMap
Java 9
Optional.stream
has been added to JDK 9. This enables you to do the following, without the need of any helper method:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(Optional::stream)
.findFirst();
Java 8
Yes, this was a small hole in the API, in that it's somewhat inconvenient to turn an Optional<T>
into a zero-or-one length Stream<T>
. You could do this:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
.findFirst();
Having the ternary operator inside the flatMap
is a bit cumbersome, though, so it might be better to write a little helper function to do this:
/**
* Turns an Optional<T> into a Stream<T> of length zero or one depending upon
* whether a value is present.
*/
static <T> Stream<T> streamopt(Optional<T> opt) {
if (opt.isPresent())
return Stream.of(opt.get());
else
return Stream.empty();
}
Optional<Other> result =
things.stream()
.flatMap(t -> streamopt(resolve(t)))
.findFirst();
Here, I've inlined the call to resolve()
instead of having a separate map()
operation, but this is a matter of taste.
Nested lists with streams in Java8
You can use two flatMap
then a filter
then you can pick the first one or if no result return null
:
C c1 = listOfAObjects.stream()
.flatMap(a -> a.getList().stream())
.flatMap(b -> b.getPr().stream())
.filter(c -> c.getName().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
How can I turn a List of Lists into a List in Java 8?
You can use flatMap
to flatten the internal lists (after converting them to Streams) into a single Stream, and then collect the result into a list:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
Related Topics
How to Serialize Joda Datetime with Jackson JSON Processor
Working with a List of Lists in Java
Reversing a String with Recursion in Java
Environment Variable to Control Java.Io.Tmpdir
Using Powermockito.Whennew() Is Not Getting Mocked and Original Method Is Called
Jpa: Unidirectional Many-To-One and Cascading Delete
How to Initialize an Arraylist with All Zeroes in Java
Check If a String Contains a Special Character
What Are "Connecting Characters" in Java Identifiers
How to Maintain Bi-Directional Relationships with Spring Data Rest and JPA
How to Connect to a SQL Server 2008 Database Using Jdbc
Text-Mouseover Popups Over a Swing Jtextarea
How to Pass List from Java to Oracle Procedure