Search code examples
javajava-8java-streamjava-9collectors

Java 8 Stream API - Java 9 Collectors.flatMapping rewritten in Java 8


I got in touch with a new feature since called Collectors.flatMapping that takes place as a downstream of grouping or partitioning. Such as (example taken from here):

List<List<Integer>> list = Arrays.asList(
    Arrays.asList(1, 2, 3, 4, 5, 6), 
    Arrays.asList(7, 8, 9, 10));

Map<Integer, List<Integer>> map =list.stream()
    .collect(Collectors.groupingBy(
         Collection::size,
         Collectors.flatMapping(
             l -> l.stream().filter(i -> i % 2 == 0),
             Collectors.toList())));

{4=[8, 10], 6=[2, 4, 6]}

This is a fairly elegant way using just 3 collectors. I need to rewrite the collector in where is not yet supported. My attempt use 6 Collectors that is quite an extensive usage and I am not able to figure out a way using less of them:

Map<Integer, List<Integer>> map = list.stream()
    .collect(Collectors.groupingBy(
        Collection::size,
        Collectors.collectingAndThen(
            Collectors.mapping(
                l -> l.stream().filter(i -> i % 2 == 0).collect(Collectors.toList()),
                Collectors.toList()),
            i -> i.stream().flatMap(j -> j.stream()).collect(Collectors.toList()))));

Is there a shorter better way using solely ?


Solution

  • For just this particular case, I guess this would be a simpler version:

    Map<Integer, List<Integer>> map =
            list.stream()
                .collect(Collectors.toMap(
                    Collection::size,
                    x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toList())
                ));
    

    If there would be merging involved (two collections that would have the same size), I would add a merge function that is pretty trivial:

     Map<Integer, List<Integer>> map =
            list.stream()
                .collect(Collectors.toMap(
                    Collection::size,
                    x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toCollection(ArrayList::new)),
                    (left, right) -> {
                        left.addAll(right);
                        return left;
                    }
                ));
    

    Otherwise, I agree with Michael in this comment, this is not that hard to back-port to java-8.