Java 9 Collectors.flatMapping rewritten in Java 8












6















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()))));


I sthere 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
    15 hours 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
    15 hours ago






  • 5





    found it...

    – Eugene
    14 hours ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    14 hours ago
















6















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()))));


I sthere 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
    15 hours 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
    15 hours ago






  • 5





    found it...

    – Eugene
    14 hours ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    14 hours ago














6












6








6


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()))));


I sthere 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()))));


I sthere 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










asked 15 hours ago









NikolasNikolas

13.3k53368




13.3k53368








  • 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
    15 hours 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
    15 hours ago






  • 5





    found it...

    – Eugene
    14 hours ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    14 hours 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
    15 hours 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
    15 hours ago






  • 5





    found it...

    – Eugene
    14 hours ago






  • 3





    @Eugene He's always 1 step ahead

    – Michael
    14 hours 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
15 hours 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
15 hours 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
15 hours 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
15 hours ago




5




5





found it...

– Eugene
14 hours ago





found it...

– Eugene
14 hours ago




3




3





@Eugene He's always 1 step ahead

– Michael
14 hours ago





@Eugene He's always 1 step ahead

– Michael
14 hours ago












2 Answers
2






active

oldest

votes


















7














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































    10














    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
      14 hours 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
      14 hours ago






    • 2





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

      – Nikolas
      13 hours 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
      13 hours ago






    • 2





      @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
      11 hours 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









    7














    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




























      7














      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


























        7












        7








        7







        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 15 hours ago









        EugeneEugene

        69.4k999164




        69.4k999164

























            10














            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
              14 hours 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
              14 hours ago






            • 2





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

              – Nikolas
              13 hours 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
              13 hours ago






            • 2





              @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
              11 hours ago
















            10














            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
              14 hours 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
              14 hours ago






            • 2





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

              – Nikolas
              13 hours 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
              13 hours ago






            • 2





              @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
              11 hours ago














            10












            10








            10







            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 14 hours ago

























            answered 14 hours ago









            MichaelMichael

            19.4k73470




            19.4k73470








            • 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
              14 hours 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
              14 hours ago






            • 2





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

              – Nikolas
              13 hours 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
              13 hours ago






            • 2





              @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
              11 hours 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
              14 hours 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
              14 hours ago






            • 2





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

              – Nikolas
              13 hours 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
              13 hours ago






            • 2





              @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
              11 hours 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
            14 hours 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
            14 hours 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
            14 hours 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
            14 hours ago




            2




            2





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

            – Nikolas
            13 hours ago





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

            – Nikolas
            13 hours 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
            13 hours 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
            13 hours ago




            2




            2





            @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
            11 hours 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
            11 hours 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

            How to make a Squid Proxy server?

            第一次世界大戦

            Touch on Surface Book