I have been checking the upcoming Java update
, namely: Java 8 or JDK 8
. Yes, I am impatient, there's a lot of new stuff, but, there is something I don't understand, some simple code:
final Stream<Integer>stream = Stream.of(1,2,3,4,5,6,7,8,9,10); stream.flatMap();
the javadocs are
public <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
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. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.) This is an intermediate operation.
I would appreciate if somebody created some simple real-life examples about flatMap
, how you could code it in previous java versions Java[6,7]
and how you can code the same routines using Java 8
.
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); }
Imagine that you want to create the following sequence: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 etc. (in other words: 1x1, 2x2, 3x3 etc.)
With flatMap
it could look like:
IntStream sequence = IntStream.rangeClosed(1, 4) .flatMap(i -> IntStream.iterate(i, identity()).limit(i)); sequence.forEach(System.out::println);
where:
IntStream.rangeClosed(1, 4)
creates a stream of int
from 1 to 4, inclusiveIntStream.iterate(i, identity()).limit(i)
creates a stream of length i of int
i - so applied to i = 4
it creates a stream: 4, 4, 4, 4
flatMap
"flattens" the stream and "concatenates" it to the original streamWith Java < 8 you would need two nested loops:
List<Integer> list = new ArrayList<>(); for (int i = 1; i <= 4; i++) { for (int j = 0; j < i; j++) { list.add(i); } }
Let's say I have a List<TimeSeries>
where each TimeSeries
is essentially a Map<LocalDate, Double>
. I want to get a list of all dates for which at least one of the time series has a value. flatMap
to the rescue:
list.stream().parallel() .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap .distinct() // remove duplicates .sorted() // sort ascending .collect(toList());
Not only is it readable, but if you suddenly need to process 100k elements, simply adding parallel()
will improve performance without you writing any concurrent code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With