Java 9 Collectors.flatMapping rewritten in Java 8












7















I got in touch with a new feature since java-9 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 java-8 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 java-8?










share|improve this question




















  • 5





    Can't you just backport flatMapping? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.

    – Michael
    2 days ago








  • 4





    @Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...

    – Eugene
    2 days ago






  • 5





    found it...

    – Eugene
    2 days ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    2 days ago
















7















I got in touch with a new feature since java-9 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 java-8 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 java-8?










share|improve this question




















  • 5





    Can't you just backport flatMapping? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.

    – Michael
    2 days ago








  • 4





    @Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...

    – Eugene
    2 days ago






  • 5





    found it...

    – Eugene
    2 days ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    2 days ago














7












7








7


1






I got in touch with a new feature since java-9 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 java-8 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 java-8?










share|improve this question
















I got in touch with a new feature since java-9 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 java-8 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 java-8?







java java-8 java-stream java-9 collectors






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday









Steephen

7,74342232




7,74342232










asked 2 days ago









NikolasNikolas

13.4k53468




13.4k53468








  • 5





    Can't you just backport flatMapping? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.

    – Michael
    2 days ago








  • 4





    @Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...

    – Eugene
    2 days ago






  • 5





    found it...

    – Eugene
    2 days ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    2 days ago














  • 5





    Can't you just backport flatMapping? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.

    – Michael
    2 days ago








  • 4





    @Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...

    – Eugene
    2 days ago






  • 5





    found it...

    – Eugene
    2 days ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    2 days ago








5




5





Can't you just backport flatMapping? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.

– Michael
2 days ago







Can't you just backport flatMapping? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.

– Michael
2 days ago






4




4





@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...

– Eugene
2 days ago





@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...

– Eugene
2 days ago




5




5





found it...

– Eugene
2 days ago





found it...

– Eugene
2 days ago




3




3





@Eugene He's always 1 step ahead

– Michael
2 days ago





@Eugene He's always 1 step ahead

– Michael
2 days ago












2 Answers
2






active

oldest

votes


















9














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.






share|improve this answer































    12














    I would just backport flatMapping. It only requires 2 methods and 1 class, with no other dependencies.



    Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.



    The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.



    Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.



    class Nikollectors
    {
    public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
    BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
    return new CollectorImpl<>(downstream.supplier(),
    (r, t) -> {
    try (Stream<? extends U> result = mapper.apply(t)) {
    if (result != null)
    result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
    }
    },
    downstream.combiner(), downstream.finisher(),
    downstream.characteristics());
    }

    private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
    {
    private final Supplier<A> supplier;
    private final BiConsumer<A, T> accumulator;
    private final BinaryOperator<A> combiner;
    private final Function<A, R> finisher;
    private final Set<Characteristics> characteristics;

    CollectorImpl(Supplier<A> supplier,
    BiConsumer<A, T> accumulator,
    BinaryOperator<A> combiner,
    Function<A,R> finisher,
    Set<Characteristics> characteristics) {
    this.supplier = supplier;
    this.accumulator = accumulator;
    this.combiner = combiner;
    this.finisher = finisher;
    this.characteristics = characteristics;
    }

    CollectorImpl(Supplier<A> supplier,
    BiConsumer<A, T> accumulator,
    BinaryOperator<A> combiner,
    Set<Characteristics> characteristics) {
    this(supplier, accumulator, combiner, castingIdentity(), characteristics);
    }

    @Override
    public BiConsumer<A, T> accumulator() {
    return accumulator;
    }

    @Override
    public Supplier<A> supplier() {
    return supplier;
    }

    @Override
    public BinaryOperator<A> combiner() {
    return combiner;
    }

    @Override
    public Function<A, R> finisher() {
    return finisher;
    }

    @Override
    public Set<Characteristics> characteristics() {
    return characteristics;
    }
    }

    private static <I, R> Function<I, R> castingIdentity() {
    return i -> (R) i;
    }
    }


    Sample usage:



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





    share|improve this answer





















    • 5





      you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

      – Eugene
      2 days ago








    • 6





      you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

      – Eugene
      2 days ago






    • 2





      You both made my day. :D Thanks for the answers and useful links.

      – Nikolas
      2 days ago






    • 3





      @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

      – Michael
      2 days ago






    • 3





      @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

      – Holger
      2 days ago











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54287457%2fjava-9-collectors-flatmapping-rewritten-in-java-8%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    9














    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.






    share|improve this answer




























      9














      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.






      share|improve this answer


























        9












        9








        9







        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.






        share|improve this answer













        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        EugeneEugene

        69.6k999164




        69.6k999164

























            12














            I would just backport flatMapping. It only requires 2 methods and 1 class, with no other dependencies.



            Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.



            The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.



            Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.



            class Nikollectors
            {
            public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
            BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
            return new CollectorImpl<>(downstream.supplier(),
            (r, t) -> {
            try (Stream<? extends U> result = mapper.apply(t)) {
            if (result != null)
            result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
            }
            },
            downstream.combiner(), downstream.finisher(),
            downstream.characteristics());
            }

            private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
            {
            private final Supplier<A> supplier;
            private final BiConsumer<A, T> accumulator;
            private final BinaryOperator<A> combiner;
            private final Function<A, R> finisher;
            private final Set<Characteristics> characteristics;

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Function<A,R> finisher,
            Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
            }

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
            }

            @Override
            public BiConsumer<A, T> accumulator() {
            return accumulator;
            }

            @Override
            public Supplier<A> supplier() {
            return supplier;
            }

            @Override
            public BinaryOperator<A> combiner() {
            return combiner;
            }

            @Override
            public Function<A, R> finisher() {
            return finisher;
            }

            @Override
            public Set<Characteristics> characteristics() {
            return characteristics;
            }
            }

            private static <I, R> Function<I, R> castingIdentity() {
            return i -> (R) i;
            }
            }


            Sample usage:



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





            share|improve this answer





















            • 5





              you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

              – Eugene
              2 days ago








            • 6





              you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

              – Eugene
              2 days ago






            • 2





              You both made my day. :D Thanks for the answers and useful links.

              – Nikolas
              2 days ago






            • 3





              @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

              – Michael
              2 days ago






            • 3





              @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

              – Holger
              2 days ago
















            12














            I would just backport flatMapping. It only requires 2 methods and 1 class, with no other dependencies.



            Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.



            The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.



            Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.



            class Nikollectors
            {
            public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
            BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
            return new CollectorImpl<>(downstream.supplier(),
            (r, t) -> {
            try (Stream<? extends U> result = mapper.apply(t)) {
            if (result != null)
            result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
            }
            },
            downstream.combiner(), downstream.finisher(),
            downstream.characteristics());
            }

            private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
            {
            private final Supplier<A> supplier;
            private final BiConsumer<A, T> accumulator;
            private final BinaryOperator<A> combiner;
            private final Function<A, R> finisher;
            private final Set<Characteristics> characteristics;

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Function<A,R> finisher,
            Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
            }

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
            }

            @Override
            public BiConsumer<A, T> accumulator() {
            return accumulator;
            }

            @Override
            public Supplier<A> supplier() {
            return supplier;
            }

            @Override
            public BinaryOperator<A> combiner() {
            return combiner;
            }

            @Override
            public Function<A, R> finisher() {
            return finisher;
            }

            @Override
            public Set<Characteristics> characteristics() {
            return characteristics;
            }
            }

            private static <I, R> Function<I, R> castingIdentity() {
            return i -> (R) i;
            }
            }


            Sample usage:



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





            share|improve this answer





















            • 5





              you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

              – Eugene
              2 days ago








            • 6





              you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

              – Eugene
              2 days ago






            • 2





              You both made my day. :D Thanks for the answers and useful links.

              – Nikolas
              2 days ago






            • 3





              @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

              – Michael
              2 days ago






            • 3





              @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

              – Holger
              2 days ago














            12












            12








            12







            I would just backport flatMapping. It only requires 2 methods and 1 class, with no other dependencies.



            Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.



            The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.



            Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.



            class Nikollectors
            {
            public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
            BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
            return new CollectorImpl<>(downstream.supplier(),
            (r, t) -> {
            try (Stream<? extends U> result = mapper.apply(t)) {
            if (result != null)
            result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
            }
            },
            downstream.combiner(), downstream.finisher(),
            downstream.characteristics());
            }

            private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
            {
            private final Supplier<A> supplier;
            private final BiConsumer<A, T> accumulator;
            private final BinaryOperator<A> combiner;
            private final Function<A, R> finisher;
            private final Set<Characteristics> characteristics;

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Function<A,R> finisher,
            Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
            }

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
            }

            @Override
            public BiConsumer<A, T> accumulator() {
            return accumulator;
            }

            @Override
            public Supplier<A> supplier() {
            return supplier;
            }

            @Override
            public BinaryOperator<A> combiner() {
            return combiner;
            }

            @Override
            public Function<A, R> finisher() {
            return finisher;
            }

            @Override
            public Set<Characteristics> characteristics() {
            return characteristics;
            }
            }

            private static <I, R> Function<I, R> castingIdentity() {
            return i -> (R) i;
            }
            }


            Sample usage:



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





            share|improve this answer















            I would just backport flatMapping. It only requires 2 methods and 1 class, with no other dependencies.



            Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.



            The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.



            Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.



            class Nikollectors
            {
            public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
            BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
            return new CollectorImpl<>(downstream.supplier(),
            (r, t) -> {
            try (Stream<? extends U> result = mapper.apply(t)) {
            if (result != null)
            result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
            }
            },
            downstream.combiner(), downstream.finisher(),
            downstream.characteristics());
            }

            private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
            {
            private final Supplier<A> supplier;
            private final BiConsumer<A, T> accumulator;
            private final BinaryOperator<A> combiner;
            private final Function<A, R> finisher;
            private final Set<Characteristics> characteristics;

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Function<A,R> finisher,
            Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
            }

            CollectorImpl(Supplier<A> supplier,
            BiConsumer<A, T> accumulator,
            BinaryOperator<A> combiner,
            Set<Characteristics> characteristics) {
            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
            }

            @Override
            public BiConsumer<A, T> accumulator() {
            return accumulator;
            }

            @Override
            public Supplier<A> supplier() {
            return supplier;
            }

            @Override
            public BinaryOperator<A> combiner() {
            return combiner;
            }

            @Override
            public Function<A, R> finisher() {
            return finisher;
            }

            @Override
            public Set<Characteristics> characteristics() {
            return characteristics;
            }
            }

            private static <I, R> Function<I, R> castingIdentity() {
            return i -> (R) i;
            }
            }


            Sample usage:



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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 2 days ago

























            answered 2 days ago









            MichaelMichael

            19.6k73470




            19.6k73470








            • 5





              you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

              – Eugene
              2 days ago








            • 6





              you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

              – Eugene
              2 days ago






            • 2





              You both made my day. :D Thanks for the answers and useful links.

              – Nikolas
              2 days ago






            • 3





              @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

              – Michael
              2 days ago






            • 3





              @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

              – Holger
              2 days ago














            • 5





              you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

              – Eugene
              2 days ago








            • 6





              you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

              – Eugene
              2 days ago






            • 2





              You both made my day. :D Thanks for the answers and useful links.

              – Nikolas
              2 days ago






            • 3





              @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

              – Michael
              2 days ago






            • 3





              @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

              – Holger
              2 days ago








            5




            5





            you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

            – Eugene
            2 days ago







            you deserve two upvotes for Nikollectors... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping to make it a full example IMHO

            – Eugene
            2 days ago






            6




            6





            you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

            – Eugene
            2 days ago





            you might be joking, but in my project we have a package xxx.HolgerUtil - just to be sure where this was taken from, no joke. :)

            – Eugene
            2 days ago




            2




            2





            You both made my day. :D Thanks for the answers and useful links.

            – Nikolas
            2 days ago





            You both made my day. :D Thanks for the answers and useful links.

            – Nikolas
            2 days ago




            3




            3





            @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

            – Michael
            2 days ago





            @Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.

            – Michael
            2 days ago




            3




            3





            @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

            – Holger
            2 days ago





            @Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a CollectorImpl class, because, in the end, there has to be an actual implementation class for the Collector interface. In your application code, you can use Collector.of(…) instead, which will use the JRE provided, non-public implementation class.

            – Holger
            2 days ago


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54287457%2fjava-9-collectors-flatmapping-rewritten-in-java-8%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

            Alcedinidae

            Origin of the phrase “under your belt”?