Java 9 Collectors.flatMapping rewritten in Java 8












9















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
    Jan 21 at 10:06








  • 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
    Jan 21 at 10:13






  • 5





    found it...

    – Eugene
    Jan 21 at 10:23






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    Jan 21 at 10:24
















9















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
    Jan 21 at 10:06








  • 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
    Jan 21 at 10:13






  • 5





    found it...

    – Eugene
    Jan 21 at 10:23






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    Jan 21 at 10:24














9












9








9


2






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 Jan 22 at 17:14









Steephen

7,85342232




7,85342232










asked Jan 21 at 10:00









NikolasNikolas

13.4k53568




13.4k53568








  • 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
    Jan 21 at 10:06








  • 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
    Jan 21 at 10:13






  • 5





    found it...

    – Eugene
    Jan 21 at 10:23






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    Jan 21 at 10:24














  • 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
    Jan 21 at 10:06








  • 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
    Jan 21 at 10:13






  • 5





    found it...

    – Eugene
    Jan 21 at 10:23






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    Jan 21 at 10:24








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
Jan 21 at 10:06







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
Jan 21 at 10:06






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
Jan 21 at 10:13





@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
Jan 21 at 10:13




5




5





found it...

– Eugene
Jan 21 at 10:23





found it...

– Eugene
Jan 21 at 10:23




3




3





@Eugene He's always 1 step ahead

– Michael
Jan 21 at 10:24





@Eugene He's always 1 step ahead

– Michael
Jan 21 at 10:24












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
      Jan 21 at 10:17








    • 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
      Jan 21 at 10:21






    • 2





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

      – Nikolas
      Jan 21 at 11:27






    • 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
      Jan 21 at 11:46






    • 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
      Jan 21 at 13:29











    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 Jan 21 at 10:12









        EugeneEugene

        70.6k9102169




        70.6k9102169

























            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
              Jan 21 at 10:17








            • 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
              Jan 21 at 10:21






            • 2





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

              – Nikolas
              Jan 21 at 11:27






            • 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
              Jan 21 at 11:46






            • 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
              Jan 21 at 13:29
















            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
              Jan 21 at 10:17








            • 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
              Jan 21 at 10:21






            • 2





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

              – Nikolas
              Jan 21 at 11:27






            • 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
              Jan 21 at 11:46






            • 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
              Jan 21 at 13:29














            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 Jan 21 at 10:22

























            answered Jan 21 at 10:16









            MichaelMichael

            20.6k83471




            20.6k83471








            • 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
              Jan 21 at 10:17








            • 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
              Jan 21 at 10:21






            • 2





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

              – Nikolas
              Jan 21 at 11:27






            • 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
              Jan 21 at 11:46






            • 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
              Jan 21 at 13:29














            • 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
              Jan 21 at 10:17








            • 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
              Jan 21 at 10:21






            • 2





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

              – Nikolas
              Jan 21 at 11:27






            • 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
              Jan 21 at 11:46






            • 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
              Jan 21 at 13:29








            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
            Jan 21 at 10:17







            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
            Jan 21 at 10:17






            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
            Jan 21 at 10:21





            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
            Jan 21 at 10:21




            2




            2





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

            – Nikolas
            Jan 21 at 11:27





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

            – Nikolas
            Jan 21 at 11:27




            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
            Jan 21 at 11:46





            @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
            Jan 21 at 11:46




            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
            Jan 21 at 13:29





            @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
            Jan 21 at 13:29


















            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

            Mario Kart Wii

            What does “Dominus providebit” mean?

            Antonio Litta Visconti Arese