Tuesday, November 13, 2018

Java 8 - Streams - flatMap()

Greetings!

With stream API it is easy to iterate over a collection and do whatever operation we like to do. Let's say we have a number list which we would like to print power of 2 of each.


List<Integer> attempt1 = Arrays.asList(1, 2, 3, 4, 5);
attempt1.stream().map(x -> x * x).forEach(System.out::println);

// 1, 4, 9, 16, 25


What if we have a List of List? let's try that out.


List<List<Integer>> attempt2 = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(2, 5));
Stream<List<Integer>> attempt2Stream = attempt2.stream();
attempt2Stream.map(x -> x * x).forEach(System.out::println); // compile error
attempt2Stream.map(x -> x.stream().map(y -> y * y)).forEach(System.out::println);

// java.util.stream.ReferencePipeline$3@4c873330, java.util.stream.ReferencePipeline$3@119d7047


As you can see Stream.map() doesn't give us the expected result for the type Stream<List<Integer>>.

This is because map() operation is the type of Stream<T> and in this case it is like a stream of stream. Not only map() operation any other operation will not give us the desired result.

This is where the Stream.flatMap() is helpful.

Stream.flatMap()

Intermediate operation. Like map() operation this accepts the mapping function and apply it to all the elements in the stream and produce a new stream as the result. Difference is this can handle any type of stream. It Flattens the input T argument and merge all the elements into new stream of type R.


<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)


This can understand with few examples.


Stream<DataType[]>>
Stream<Set<DataType>>
Stream<List<DataType>>
Stream<Map<KEY, DataType>


This all can be easily mapped to Stream<DataType> with flatMa(). After flattening we can do any other operation.

Array - Stream<DataType[]>


import java.util.Arrays;
import java.util.stream.Stream;

public class FlatMapArray {

    public static void main(String[] args) {
        Integer[][] array = { { 1, 2, 3 }, { 4, 5 } };
        Stream<Integer[]> stream = Arrays.stream(array);

//        stream.flatMap(subarray -> Arrays.stream(subarray)).map(x -> x * x).forEach(System.out::println);
        stream.flatMap(Arrays::stream).map(x -> x * x).forEach(System.out::println);
    }

}

// 1, 4, 9, 16, 25


List - Stream<List<DataType>>


import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;

public class FlatMapList {

    public static void main(String[] args) {
        List<List<Integer>> lists = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(2, 5));
        Stream<List<Integer>> stream = lists.stream();

//        stream.flatMap(list -> list.stream()).distinct().map(x -> x * x).forEach(System.out::println);
        stream.flatMap(Collection::stream).distinct().map(x -> x * x).forEach(System.out::println);
    }

}

// 1, 4, 9, 25


Map - Stream<Map<Key, Datatype>>


import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

public class FlatMapMap {

    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "one");
        map.put(2, "two");
        map.put(3, "three");
        
        Stream<Map<Integer, String>> streamMap = Stream.of(map);
        
        streamMap.flatMap(m -> m.values().stream()).map(String::toUpperCase).forEach(System.out::println);
    }

}

// ONE, TWO, THREE


Set - Stream<Set<DataType>>


import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

public class FlatMapSet {

    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("one");
        set.add("two");
        set.add("three");
        
        Stream<Set<String>> streamSet = Stream.of(set);
        
        streamSet.flatMap(Collection::stream).map(String::toUpperCase).forEach(System.out::println);
    }

}

// ONE, TWO, THREE


In summary these operations behave like this; (DataType is String here)

Stream<String> flatMap(Function<String[], Stream<String>> mapper)

Stream<String> flatMap(Function<List<String>, Stream<String>> mapper)

Stream<String> flatMap(Function<Set<String>, Stream<String>> mapper)

Stream<String> flatMap(Function<Map<Integer, String>, Stream<String>> mapper)




No comments:

Post a Comment