How does the reduce() method work in Java 8?In Stream reduce method, must the identity always be 0 for sum and 1 for multiplication?Is Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?Does a finally block always get executed in Java?How does the Java 'for each' loop work?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?How do I convert a String to an int in Java?Creating a memory leak with JavaJava 8 List<V> into Map<K, V>

Acronyms in HDD specification

Why are solar panels kept tilted?

Offered a new position but unknown about salary?

Why does SSL Labs now consider CBC suites weak?

Is it wrong to omit object pronouns in these sentences?

"The van's really booking"

Is there any good reason to write "it is easy to see"?

How to continually let my readers know what time it is in my story, in an organic way?

Is this possible when it comes to the relations of P, NP, NP-Hard and NP-Complete?

Wireless headphones interfere with Wi-Fi signal on laptop

Why are BJTs common in output stages of power amplifiers?

How do I adjust encounters to challenge my lycanthrope players without negating their cool new abilities?

Is there any way to adjust the damage type of the Eldritch Blast cantrip so that it does fire damage?

Were any toxic metals used in the International Space Station?

Should generated documentation be stored in a Git repository?

Why is it harder to turn a motor/generator with shorted terminals?

How can a layman easily get the consensus view of what academia *thinks* about a subject?

Substring join or additional table, which is faster?

Biology of a Firestarter

Why can't I share a one use code with anyone else?

Is there an academic word that means "to split hairs over"?

Why did the soldiers of the North disobey Jon?

Can my Serbian girlfriend apply for a UK Standard Visitor visa and stay for the whole 6 months?

Was the dragon prowess intentionally downplayed in S08E04?



How does the reduce() method work in Java 8?


In Stream reduce method, must the identity always be 0 for sum and 1 for multiplication?Is Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?Does a finally block always get executed in Java?How does the Java 'for each' loop work?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?How do I convert a String to an int in Java?Creating a memory leak with JavaJava 8 List<V> into Map<K, V>






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








17















I try to understand how does the reduce() method work in java-8.



For example I have this code:



public class App 

public static void main(String[] args)
String[] arr = "lorem", "ipsum", "sit", "amet";
List<String> strs = Arrays.asList(arr);

int ijk = strs.stream().reduce(0,
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);
System.out.println(ijk);




And the output is this:



Accumulator, a = 0, b = lorem
Accumulator, a = 5, b = ipsum
Accumulator, a = 10, b = sit
Accumulator, a = 13, b = amet
17


It is a sum of the length of these strings. And I see that the combiner is not accessed, so it will not multiply the numbers, it only adds the numbers.



But if I have these stream:



int ijk = strs.parallelStream().reduce(0, 
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);

System.out.println(ijk);


This is the output:



Accumulator, a = 0, b = ipsum
Accumulator, a = 0, b = lorem
Accumulator, a = 0, b = sit
Combiner
Accumulator, a = 0, b = amet
Combiner
Combiner
300


I see that the Accumulator and Combiner are accessed both, but only the multiplication is return. So what's happen with the sum?










share|improve this question



















  • 6





    combiner is only called for a parallel stream. also read the documentation of reduce carefully, you can not do summation in accumulator and multiplication in combiner and expect something meaningful as a result

    – Eugene
    May 3 at 12:50


















17















I try to understand how does the reduce() method work in java-8.



For example I have this code:



public class App 

public static void main(String[] args)
String[] arr = "lorem", "ipsum", "sit", "amet";
List<String> strs = Arrays.asList(arr);

int ijk = strs.stream().reduce(0,
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);
System.out.println(ijk);




And the output is this:



Accumulator, a = 0, b = lorem
Accumulator, a = 5, b = ipsum
Accumulator, a = 10, b = sit
Accumulator, a = 13, b = amet
17


It is a sum of the length of these strings. And I see that the combiner is not accessed, so it will not multiply the numbers, it only adds the numbers.



But if I have these stream:



int ijk = strs.parallelStream().reduce(0, 
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);

System.out.println(ijk);


This is the output:



Accumulator, a = 0, b = ipsum
Accumulator, a = 0, b = lorem
Accumulator, a = 0, b = sit
Combiner
Accumulator, a = 0, b = amet
Combiner
Combiner
300


I see that the Accumulator and Combiner are accessed both, but only the multiplication is return. So what's happen with the sum?










share|improve this question



















  • 6





    combiner is only called for a parallel stream. also read the documentation of reduce carefully, you can not do summation in accumulator and multiplication in combiner and expect something meaningful as a result

    – Eugene
    May 3 at 12:50














17












17








17


5






I try to understand how does the reduce() method work in java-8.



For example I have this code:



public class App 

public static void main(String[] args)
String[] arr = "lorem", "ipsum", "sit", "amet";
List<String> strs = Arrays.asList(arr);

int ijk = strs.stream().reduce(0,
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);
System.out.println(ijk);




And the output is this:



Accumulator, a = 0, b = lorem
Accumulator, a = 5, b = ipsum
Accumulator, a = 10, b = sit
Accumulator, a = 13, b = amet
17


It is a sum of the length of these strings. And I see that the combiner is not accessed, so it will not multiply the numbers, it only adds the numbers.



But if I have these stream:



int ijk = strs.parallelStream().reduce(0, 
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);

System.out.println(ijk);


This is the output:



Accumulator, a = 0, b = ipsum
Accumulator, a = 0, b = lorem
Accumulator, a = 0, b = sit
Combiner
Accumulator, a = 0, b = amet
Combiner
Combiner
300


I see that the Accumulator and Combiner are accessed both, but only the multiplication is return. So what's happen with the sum?










share|improve this question
















I try to understand how does the reduce() method work in java-8.



For example I have this code:



public class App 

public static void main(String[] args)
String[] arr = "lorem", "ipsum", "sit", "amet";
List<String> strs = Arrays.asList(arr);

int ijk = strs.stream().reduce(0,
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);
System.out.println(ijk);




And the output is this:



Accumulator, a = 0, b = lorem
Accumulator, a = 5, b = ipsum
Accumulator, a = 10, b = sit
Accumulator, a = 13, b = amet
17


It is a sum of the length of these strings. And I see that the combiner is not accessed, so it will not multiply the numbers, it only adds the numbers.



But if I have these stream:



int ijk = strs.parallelStream().reduce(0, 
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a * b;
);

System.out.println(ijk);


This is the output:



Accumulator, a = 0, b = ipsum
Accumulator, a = 0, b = lorem
Accumulator, a = 0, b = sit
Combiner
Accumulator, a = 0, b = amet
Combiner
Combiner
300


I see that the Accumulator and Combiner are accessed both, but only the multiplication is return. So what's happen with the sum?







java java-8 java-stream reduce






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 3 at 13:30









Nikolas

14.9k53871




14.9k53871










asked May 3 at 12:47









gabygaby

701214




701214







  • 6





    combiner is only called for a parallel stream. also read the documentation of reduce carefully, you can not do summation in accumulator and multiplication in combiner and expect something meaningful as a result

    – Eugene
    May 3 at 12:50













  • 6





    combiner is only called for a parallel stream. also read the documentation of reduce carefully, you can not do summation in accumulator and multiplication in combiner and expect something meaningful as a result

    – Eugene
    May 3 at 12:50








6




6





combiner is only called for a parallel stream. also read the documentation of reduce carefully, you can not do summation in accumulator and multiplication in combiner and expect something meaningful as a result

– Eugene
May 3 at 12:50






combiner is only called for a parallel stream. also read the documentation of reduce carefully, you can not do summation in accumulator and multiplication in combiner and expect something meaningful as a result

– Eugene
May 3 at 12:50













4 Answers
4






active

oldest

votes


















16














You should read the documentation of reduce that says:




Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:



combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)




In your case, you are breaking that law (doing a sum in accumulator and multiplication in the combiner), so the result you see for such an operation is really undefined and depends on how the Spliterator for the underlying source is implemented (don't do that!).



Besides, the combiner is only called for a parallel stream.



Of course, your entire approach could be simplified to:



Arrays.asList("lorem", "ipsum", "sit", "amet")
.stream()
.mapToInt(String::length)
.sum();


If you are doing that just for learning purposes, a correct reduce would be (to get the sum):



strs.parallelStream()
.reduce(0,
(a, b) ->
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
,
(a, b) ->
System.out.println("Combiner");
return a + b;
);





share|improve this answer
































    8














    The Key Concepts: Identity, Accumulator, and Combiner



    Stream.reduce() operation : let’s break down the operation’s participant elements into separate blocks. That way, we’ll understand more easily the role that each one plays




    • Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty


    • itemAccumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream


    • Combiner – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
      Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized, or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation


    When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner




    Case 1 : Combiner works with parallelStream as showed in your example



    Case 2 : Example accumulator with different type of arguments



    In this case, we have a stream of User objects, and the types of the accumulator arguments are Integer and User. However, the accumulator implementation is a sum of Integers, so the compiler just can’t infer the type of the user parameter.



    List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
    int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());


    Compile Error



    The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> )


    We can fix this issue by using a combiner: which is method reference Integer::sum or by using lambda expression (a,b)->a+b



    int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);


    To put it simply, if we use sequential streams and the types of the accumulator arguments and the types of its implementation match, we don’t need to use a combiner.






    share|improve this answer
































      8














      There are 3 ways to reduce using java-stream. In a nutshell, Stream::reduce starts with two consequent items (or an identity value one with the first one) and performs an operation with them producing new reduced value. For each next item, the same happens and an operation is performed with the reduced value.



      Let's say you have a stream of 'a', 'b', 'c' and 'd'. The reduction performs the following sequence of operations:




      1. result = operationOn('a', 'b') - the operationOn might be anything (sum of the lengths of inputs..)

      2. result = operationOn(result, 'c')

      3. result = operationOn(result, 'd')

      4. result is returned

      The methods are:



      • Optional<T> reduce(BinaryOperator<T> accumulator) performs a reduction on the elements. Starts with the first two items producing a reduced value, then each item with the reduced value. The Optional<T> is returned since it is not guaranteed the input stream is not empty.


      • T reduce(T identity, BinaryOperator<T> accumulator) does the same as the method above, except the identity value is given as the first item. The T is returned since there is always at least one item guaranteed, because of T identity.


      • U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner) does the same as the method above, with an addition that the functions are combined. The U is returned since there is always at least one item guaranteed, because of U identity.






      share|improve this answer

























      • Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

        – Holger
        May 6 at 10:46











      • "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

        – Nikolas
        May 6 at 10:48











      • Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

        – Holger
        May 6 at 10:51


















      1














      I assume you chose to do addition and multiplication just as a demo to see what exactly happens.



      As you already noticed, and as was already mentioned, the combiner is only called on parallel streams.



      In short, on parallel strams, a part of the stream (resp. the underlying Spliterator) is cut off and processed by a different thread. After several parts are processed, their result is combined with a combiner.



      In your case, the four elements all are processed by a different thread, and combination happens element-wise then. That's why you don't see any addition (apart from 0 +) being applied, but only multiplication.



      In order to get a meaningful result, however, you should switch from * to + and instead do a more meaningful output.






      share|improve this answer























        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%2f55970149%2fhow-does-the-reduce-method-work-in-java-8%23new-answer', 'question_page');

        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        16














        You should read the documentation of reduce that says:




        Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:



        combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)




        In your case, you are breaking that law (doing a sum in accumulator and multiplication in the combiner), so the result you see for such an operation is really undefined and depends on how the Spliterator for the underlying source is implemented (don't do that!).



        Besides, the combiner is only called for a parallel stream.



        Of course, your entire approach could be simplified to:



        Arrays.asList("lorem", "ipsum", "sit", "amet")
        .stream()
        .mapToInt(String::length)
        .sum();


        If you are doing that just for learning purposes, a correct reduce would be (to get the sum):



        strs.parallelStream()
        .reduce(0,
        (a, b) ->
        System.out.println("Accumulator, a = " + a + ", b = " + b);
        return a + b.length();
        ,
        (a, b) ->
        System.out.println("Combiner");
        return a + b;
        );





        share|improve this answer





























          16














          You should read the documentation of reduce that says:




          Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:



          combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)




          In your case, you are breaking that law (doing a sum in accumulator and multiplication in the combiner), so the result you see for such an operation is really undefined and depends on how the Spliterator for the underlying source is implemented (don't do that!).



          Besides, the combiner is only called for a parallel stream.



          Of course, your entire approach could be simplified to:



          Arrays.asList("lorem", "ipsum", "sit", "amet")
          .stream()
          .mapToInt(String::length)
          .sum();


          If you are doing that just for learning purposes, a correct reduce would be (to get the sum):



          strs.parallelStream()
          .reduce(0,
          (a, b) ->
          System.out.println("Accumulator, a = " + a + ", b = " + b);
          return a + b.length();
          ,
          (a, b) ->
          System.out.println("Combiner");
          return a + b;
          );





          share|improve this answer



























            16












            16








            16







            You should read the documentation of reduce that says:




            Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:



            combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)




            In your case, you are breaking that law (doing a sum in accumulator and multiplication in the combiner), so the result you see for such an operation is really undefined and depends on how the Spliterator for the underlying source is implemented (don't do that!).



            Besides, the combiner is only called for a parallel stream.



            Of course, your entire approach could be simplified to:



            Arrays.asList("lorem", "ipsum", "sit", "amet")
            .stream()
            .mapToInt(String::length)
            .sum();


            If you are doing that just for learning purposes, a correct reduce would be (to get the sum):



            strs.parallelStream()
            .reduce(0,
            (a, b) ->
            System.out.println("Accumulator, a = " + a + ", b = " + b);
            return a + b.length();
            ,
            (a, b) ->
            System.out.println("Combiner");
            return a + b;
            );





            share|improve this answer















            You should read the documentation of reduce that says:




            Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:



            combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)




            In your case, you are breaking that law (doing a sum in accumulator and multiplication in the combiner), so the result you see for such an operation is really undefined and depends on how the Spliterator for the underlying source is implemented (don't do that!).



            Besides, the combiner is only called for a parallel stream.



            Of course, your entire approach could be simplified to:



            Arrays.asList("lorem", "ipsum", "sit", "amet")
            .stream()
            .mapToInt(String::length)
            .sum();


            If you are doing that just for learning purposes, a correct reduce would be (to get the sum):



            strs.parallelStream()
            .reduce(0,
            (a, b) ->
            System.out.println("Accumulator, a = " + a + ", b = " + b);
            return a + b.length();
            ,
            (a, b) ->
            System.out.println("Combiner");
            return a + b;
            );






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited May 3 at 13:12









            John Kugelman

            251k55411463




            251k55411463










            answered May 3 at 12:57









            EugeneEugene

            73.7k9104179




            73.7k9104179























                8














                The Key Concepts: Identity, Accumulator, and Combiner



                Stream.reduce() operation : let’s break down the operation’s participant elements into separate blocks. That way, we’ll understand more easily the role that each one plays




                • Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty


                • itemAccumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream


                • Combiner – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
                  Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized, or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation


                When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner




                Case 1 : Combiner works with parallelStream as showed in your example



                Case 2 : Example accumulator with different type of arguments



                In this case, we have a stream of User objects, and the types of the accumulator arguments are Integer and User. However, the accumulator implementation is a sum of Integers, so the compiler just can’t infer the type of the user parameter.



                List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
                int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());


                Compile Error



                The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> )


                We can fix this issue by using a combiner: which is method reference Integer::sum or by using lambda expression (a,b)->a+b



                int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);


                To put it simply, if we use sequential streams and the types of the accumulator arguments and the types of its implementation match, we don’t need to use a combiner.






                share|improve this answer





























                  8














                  The Key Concepts: Identity, Accumulator, and Combiner



                  Stream.reduce() operation : let’s break down the operation’s participant elements into separate blocks. That way, we’ll understand more easily the role that each one plays




                  • Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty


                  • itemAccumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream


                  • Combiner – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
                    Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized, or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation


                  When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner




                  Case 1 : Combiner works with parallelStream as showed in your example



                  Case 2 : Example accumulator with different type of arguments



                  In this case, we have a stream of User objects, and the types of the accumulator arguments are Integer and User. However, the accumulator implementation is a sum of Integers, so the compiler just can’t infer the type of the user parameter.



                  List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
                  int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());


                  Compile Error



                  The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> )


                  We can fix this issue by using a combiner: which is method reference Integer::sum or by using lambda expression (a,b)->a+b



                  int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);


                  To put it simply, if we use sequential streams and the types of the accumulator arguments and the types of its implementation match, we don’t need to use a combiner.






                  share|improve this answer



























                    8












                    8








                    8







                    The Key Concepts: Identity, Accumulator, and Combiner



                    Stream.reduce() operation : let’s break down the operation’s participant elements into separate blocks. That way, we’ll understand more easily the role that each one plays




                    • Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty


                    • itemAccumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream


                    • Combiner – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
                      Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized, or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation


                    When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner




                    Case 1 : Combiner works with parallelStream as showed in your example



                    Case 2 : Example accumulator with different type of arguments



                    In this case, we have a stream of User objects, and the types of the accumulator arguments are Integer and User. However, the accumulator implementation is a sum of Integers, so the compiler just can’t infer the type of the user parameter.



                    List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
                    int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());


                    Compile Error



                    The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> )


                    We can fix this issue by using a combiner: which is method reference Integer::sum or by using lambda expression (a,b)->a+b



                    int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);


                    To put it simply, if we use sequential streams and the types of the accumulator arguments and the types of its implementation match, we don’t need to use a combiner.






                    share|improve this answer















                    The Key Concepts: Identity, Accumulator, and Combiner



                    Stream.reduce() operation : let’s break down the operation’s participant elements into separate blocks. That way, we’ll understand more easily the role that each one plays




                    • Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty


                    • itemAccumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream


                    • Combiner – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
                      Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized, or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation


                    When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner




                    Case 1 : Combiner works with parallelStream as showed in your example



                    Case 2 : Example accumulator with different type of arguments



                    In this case, we have a stream of User objects, and the types of the accumulator arguments are Integer and User. However, the accumulator implementation is a sum of Integers, so the compiler just can’t infer the type of the user parameter.



                    List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
                    int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());


                    Compile Error



                    The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> )


                    We can fix this issue by using a combiner: which is method reference Integer::sum or by using lambda expression (a,b)->a+b



                    int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);


                    To put it simply, if we use sequential streams and the types of the accumulator arguments and the types of its implementation match, we don’t need to use a combiner.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited May 3 at 15:12

























                    answered May 3 at 13:00









                    DeadpoolDeadpool

                    9,0022831




                    9,0022831





















                        8














                        There are 3 ways to reduce using java-stream. In a nutshell, Stream::reduce starts with two consequent items (or an identity value one with the first one) and performs an operation with them producing new reduced value. For each next item, the same happens and an operation is performed with the reduced value.



                        Let's say you have a stream of 'a', 'b', 'c' and 'd'. The reduction performs the following sequence of operations:




                        1. result = operationOn('a', 'b') - the operationOn might be anything (sum of the lengths of inputs..)

                        2. result = operationOn(result, 'c')

                        3. result = operationOn(result, 'd')

                        4. result is returned

                        The methods are:



                        • Optional<T> reduce(BinaryOperator<T> accumulator) performs a reduction on the elements. Starts with the first two items producing a reduced value, then each item with the reduced value. The Optional<T> is returned since it is not guaranteed the input stream is not empty.


                        • T reduce(T identity, BinaryOperator<T> accumulator) does the same as the method above, except the identity value is given as the first item. The T is returned since there is always at least one item guaranteed, because of T identity.


                        • U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner) does the same as the method above, with an addition that the functions are combined. The U is returned since there is always at least one item guaranteed, because of U identity.






                        share|improve this answer

























                        • Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

                          – Holger
                          May 6 at 10:46











                        • "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

                          – Nikolas
                          May 6 at 10:48











                        • Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

                          – Holger
                          May 6 at 10:51















                        8














                        There are 3 ways to reduce using java-stream. In a nutshell, Stream::reduce starts with two consequent items (or an identity value one with the first one) and performs an operation with them producing new reduced value. For each next item, the same happens and an operation is performed with the reduced value.



                        Let's say you have a stream of 'a', 'b', 'c' and 'd'. The reduction performs the following sequence of operations:




                        1. result = operationOn('a', 'b') - the operationOn might be anything (sum of the lengths of inputs..)

                        2. result = operationOn(result, 'c')

                        3. result = operationOn(result, 'd')

                        4. result is returned

                        The methods are:



                        • Optional<T> reduce(BinaryOperator<T> accumulator) performs a reduction on the elements. Starts with the first two items producing a reduced value, then each item with the reduced value. The Optional<T> is returned since it is not guaranteed the input stream is not empty.


                        • T reduce(T identity, BinaryOperator<T> accumulator) does the same as the method above, except the identity value is given as the first item. The T is returned since there is always at least one item guaranteed, because of T identity.


                        • U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner) does the same as the method above, with an addition that the functions are combined. The U is returned since there is always at least one item guaranteed, because of U identity.






                        share|improve this answer

























                        • Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

                          – Holger
                          May 6 at 10:46











                        • "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

                          – Nikolas
                          May 6 at 10:48











                        • Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

                          – Holger
                          May 6 at 10:51













                        8












                        8








                        8







                        There are 3 ways to reduce using java-stream. In a nutshell, Stream::reduce starts with two consequent items (or an identity value one with the first one) and performs an operation with them producing new reduced value. For each next item, the same happens and an operation is performed with the reduced value.



                        Let's say you have a stream of 'a', 'b', 'c' and 'd'. The reduction performs the following sequence of operations:




                        1. result = operationOn('a', 'b') - the operationOn might be anything (sum of the lengths of inputs..)

                        2. result = operationOn(result, 'c')

                        3. result = operationOn(result, 'd')

                        4. result is returned

                        The methods are:



                        • Optional<T> reduce(BinaryOperator<T> accumulator) performs a reduction on the elements. Starts with the first two items producing a reduced value, then each item with the reduced value. The Optional<T> is returned since it is not guaranteed the input stream is not empty.


                        • T reduce(T identity, BinaryOperator<T> accumulator) does the same as the method above, except the identity value is given as the first item. The T is returned since there is always at least one item guaranteed, because of T identity.


                        • U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner) does the same as the method above, with an addition that the functions are combined. The U is returned since there is always at least one item guaranteed, because of U identity.






                        share|improve this answer















                        There are 3 ways to reduce using java-stream. In a nutshell, Stream::reduce starts with two consequent items (or an identity value one with the first one) and performs an operation with them producing new reduced value. For each next item, the same happens and an operation is performed with the reduced value.



                        Let's say you have a stream of 'a', 'b', 'c' and 'd'. The reduction performs the following sequence of operations:




                        1. result = operationOn('a', 'b') - the operationOn might be anything (sum of the lengths of inputs..)

                        2. result = operationOn(result, 'c')

                        3. result = operationOn(result, 'd')

                        4. result is returned

                        The methods are:



                        • Optional<T> reduce(BinaryOperator<T> accumulator) performs a reduction on the elements. Starts with the first two items producing a reduced value, then each item with the reduced value. The Optional<T> is returned since it is not guaranteed the input stream is not empty.


                        • T reduce(T identity, BinaryOperator<T> accumulator) does the same as the method above, except the identity value is given as the first item. The T is returned since there is always at least one item guaranteed, because of T identity.


                        • U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner) does the same as the method above, with an addition that the functions are combined. The U is returned since there is always at least one item guaranteed, because of U identity.







                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited May 6 at 10:54

























                        answered May 3 at 13:08









                        NikolasNikolas

                        14.9k53871




                        14.9k53871












                        • Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

                          – Holger
                          May 6 at 10:46











                        • "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

                          – Nikolas
                          May 6 at 10:48











                        • Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

                          – Holger
                          May 6 at 10:51

















                        • Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

                          – Holger
                          May 6 at 10:46











                        • "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

                          – Nikolas
                          May 6 at 10:48











                        • Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

                          – Holger
                          May 6 at 10:51
















                        Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

                        – Holger
                        May 6 at 10:46





                        Calling the identity value a “default value” is misleading, if not worse. If you want a default value, use reduce(function).orElse(default). Further, the explanation for the 3rd overload, “with an addition that the functions are combined” is not really helpful. The point of the third version is, that it allows to reduce to a different result type than the Stream’s element type. The difference to the straight-forward alternative, stream.map(…).reduce(id, function) is that you can use an optimized function for combining a source element (T) with a result element (U), if there as one.

                        – Holger
                        May 6 at 10:46













                        "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

                        – Nikolas
                        May 6 at 10:48





                        "initial" might be better than "default" right? I still improve my English. Thanks for a note :)

                        – Nikolas
                        May 6 at 10:48













                        Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

                        – Holger
                        May 6 at 10:51





                        Well, the term “identity value” is already a term on its own, which has no better replacement. Neither “initial” nor “default” will be sufficient. The contract of an identity value is explained right in the documentation, but, as explained in this answer, it’s a term, not just invented for the reduction operation.

                        – Holger
                        May 6 at 10:51











                        1














                        I assume you chose to do addition and multiplication just as a demo to see what exactly happens.



                        As you already noticed, and as was already mentioned, the combiner is only called on parallel streams.



                        In short, on parallel strams, a part of the stream (resp. the underlying Spliterator) is cut off and processed by a different thread. After several parts are processed, their result is combined with a combiner.



                        In your case, the four elements all are processed by a different thread, and combination happens element-wise then. That's why you don't see any addition (apart from 0 +) being applied, but only multiplication.



                        In order to get a meaningful result, however, you should switch from * to + and instead do a more meaningful output.






                        share|improve this answer



























                          1














                          I assume you chose to do addition and multiplication just as a demo to see what exactly happens.



                          As you already noticed, and as was already mentioned, the combiner is only called on parallel streams.



                          In short, on parallel strams, a part of the stream (resp. the underlying Spliterator) is cut off and processed by a different thread. After several parts are processed, their result is combined with a combiner.



                          In your case, the four elements all are processed by a different thread, and combination happens element-wise then. That's why you don't see any addition (apart from 0 +) being applied, but only multiplication.



                          In order to get a meaningful result, however, you should switch from * to + and instead do a more meaningful output.






                          share|improve this answer

























                            1












                            1








                            1







                            I assume you chose to do addition and multiplication just as a demo to see what exactly happens.



                            As you already noticed, and as was already mentioned, the combiner is only called on parallel streams.



                            In short, on parallel strams, a part of the stream (resp. the underlying Spliterator) is cut off and processed by a different thread. After several parts are processed, their result is combined with a combiner.



                            In your case, the four elements all are processed by a different thread, and combination happens element-wise then. That's why you don't see any addition (apart from 0 +) being applied, but only multiplication.



                            In order to get a meaningful result, however, you should switch from * to + and instead do a more meaningful output.






                            share|improve this answer













                            I assume you chose to do addition and multiplication just as a demo to see what exactly happens.



                            As you already noticed, and as was already mentioned, the combiner is only called on parallel streams.



                            In short, on parallel strams, a part of the stream (resp. the underlying Spliterator) is cut off and processed by a different thread. After several parts are processed, their result is combined with a combiner.



                            In your case, the four elements all are processed by a different thread, and combination happens element-wise then. That's why you don't see any addition (apart from 0 +) being applied, but only multiplication.



                            In order to get a meaningful result, however, you should switch from * to + and instead do a more meaningful output.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered May 3 at 12:56









                            glglglglglgl

                            68.7k796169




                            68.7k796169



























                                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%2f55970149%2fhow-does-the-reduce-method-work-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

                                Wikipedia:Vital articles Мазмуну Biography - Өмүр баян Philosophy and psychology - Философия жана психология Religion - Дин Social sciences - Коомдук илимдер Language and literature - Тил жана адабият Science - Илим Technology - Технология Arts and recreation - Искусство жана эс алуу History and geography - Тарых жана география Навигация менюсу

                                Bruxelas-Capital Índice Historia | Composición | Situación lingüística | Clima | Cidades irmandadas | Notas | Véxase tamén | Menú de navegacióneO uso das linguas en Bruxelas e a situación do neerlandés"Rexión de Bruxelas Capital"o orixinalSitio da rexiónPáxina de Bruselas no sitio da Oficina de Promoción Turística de Valonia e BruxelasMapa Interactivo da Rexión de Bruxelas-CapitaleeWorldCat332144929079854441105155190212ID28008674080552-90000 0001 0666 3698n94104302ID540940339365017018237

                                What should I write in an apology letter, since I have decided not to join a company after accepting an offer letterShould I keep looking after accepting a job offer?What should I do when I've been verbally told I would get an offer letter, but still haven't gotten one after 4 weeks?Do I accept an offer from a company that I am not likely to join?New job hasn't confirmed starting date and I want to give current employer as much notice as possibleHow should I address my manager in my resignation letter?HR delayed background verification, now jobless as resignedNo email communication after accepting a formal written offer. How should I phrase the call?What should I do if after receiving a verbal offer letter I am informed that my written job offer is put on hold due to some internal issues?Should I inform the current employer that I am about to resign within 1-2 weeks since I have signed the offer letter and waiting for visa?What company will do, if I send their offer letter to another company