What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how...











up vote
3
down vote

favorite
1












What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how many items were processed, assuming I want to process the stream only once and not mutate a variable outside the lambda?










share|improve this question


















  • 1




    What do you mean by process? map() or forEach()?
    – biziclop
    Feb 2 '17 at 11:51















up vote
3
down vote

favorite
1












What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how many items were processed, assuming I want to process the stream only once and not mutate a variable outside the lambda?










share|improve this question


















  • 1




    What do you mean by process? map() or forEach()?
    – biziclop
    Feb 2 '17 at 11:51













up vote
3
down vote

favorite
1









up vote
3
down vote

favorite
1






1





What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how many items were processed, assuming I want to process the stream only once and not mutate a variable outside the lambda?










share|improve this question













What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how many items were processed, assuming I want to process the stream only once and not mutate a variable outside the lambda?







java-8






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 2 '17 at 6:18









Gabriel C

4031417




4031417








  • 1




    What do you mean by process? map() or forEach()?
    – biziclop
    Feb 2 '17 at 11:51














  • 1




    What do you mean by process? map() or forEach()?
    – biziclop
    Feb 2 '17 at 11:51








1




1




What do you mean by process? map() or forEach()?
– biziclop
Feb 2 '17 at 11:51




What do you mean by process? map() or forEach()?
– biziclop
Feb 2 '17 at 11:51












4 Answers
4






active

oldest

votes

















up vote
6
down vote



accepted










It might be tempting to use



long count = stream.peek(action).count();


and it may appear to work. However, peek’s action will only be performed when an element is being processed, but for some streams, the count may be available without processing the elements. Java 9 is going to take this opportunity, which makes the code above fail to perform action for some streams.



You can use a collect operation that doesn’t allow to take short-cuts, e.g.



long count = stream.collect(
Collectors.mapping(s -> { action.accept(s); return s; }, Collectors.counting()));


or



long count = stream.collect(Collectors.summingLong(s -> { action.accept(s); return 1; }));





share|improve this answer




























    up vote
    2
    down vote













    I would go with a reduce operation of some sort, something like this:



     int howMany = Stream.of("a", "vc", "ads", "ts", "ta").reduce(0, (i, string) -> {
    if (string.contains("a")) {
    // process a in any other way
    return i+1;
    }
    return i;
    }, (left, right) -> null); // override if parallel stream required

    System.out.println(howMany);





    share|improve this answer



















    • 2




      The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
      – Holger
      Feb 2 '17 at 12:01


















    up vote
    0
    down vote













    This can be done with peek function, as it returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.



    AtomicInteger counter = new AtomicInteger(0);

    elements
    .stream()
    .forEach(doSomething())
    .peek(elem -> counter.incrementAndGet());

    int elementsProcessed = counter.get();





    share|improve this answer

















    • 3




      and not mutate a variable outside the lambda
      – Eugene
      Feb 2 '17 at 8:47






    • 4




      Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
      – Holger
      Feb 2 '17 at 11:38










    • forEach returns void and the suggested code doesn't compile.
      – Gabriel C
      Feb 2 '17 at 23:08


















    up vote
    0
    down vote













    Streams are lazily evaluated and therefore processed in a single step, combining all intermediate operations when a final operation is called, no matter how many operations you perform over them.



    This way, you don't have to worry because your stream will be processed at once. But the best way to perform some operation on each stream's element and count the number of elements processed depends on your goal.
    Anyway, the two examples below don't mutate a variable to perform that count.



    Both examples create a Stream of Strings, perform a trim() on each String to remove blank spaces and then, filter the Strings that have some content.



    Example 1



    Uses the peek method to perform some operation over each filtered string. In this case, just print each one. Finally, it just uses the count() to get how many Strings were processed.



    Stream<String> stream = 
    Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
    long count = stream
    .map(String::trim)
    .filter(s -> !s.isEmpty())
    .peek(System.out::println)
    .count();

    System.out.printf(
    "nNumber of non-empty strings after a trim() operation: %dnn", count);


    Example 2



    Uses the collect method after filtering and mapping to get all the processed Strings into a List. By this way, the List can be printed separately and the number of elements got from list.size()



    Stream<String> stream = 
    Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
    List<String> list = stream
    .map(String::trim)
    .filter(s -> !s.isEmpty())
    .collect(Collectors.toList());

    list.forEach(System.out::println);
    System.out.printf(
    "nNumber of non-empty strings after a trim() operation: %dnn", list.size());





    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',
      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%2f41995426%2fwhat-is-the-most-elegant-way-to-run-a-lambda-for-each-element-of-a-java-8-stream%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








      up vote
      6
      down vote



      accepted










      It might be tempting to use



      long count = stream.peek(action).count();


      and it may appear to work. However, peek’s action will only be performed when an element is being processed, but for some streams, the count may be available without processing the elements. Java 9 is going to take this opportunity, which makes the code above fail to perform action for some streams.



      You can use a collect operation that doesn’t allow to take short-cuts, e.g.



      long count = stream.collect(
      Collectors.mapping(s -> { action.accept(s); return s; }, Collectors.counting()));


      or



      long count = stream.collect(Collectors.summingLong(s -> { action.accept(s); return 1; }));





      share|improve this answer

























        up vote
        6
        down vote



        accepted










        It might be tempting to use



        long count = stream.peek(action).count();


        and it may appear to work. However, peek’s action will only be performed when an element is being processed, but for some streams, the count may be available without processing the elements. Java 9 is going to take this opportunity, which makes the code above fail to perform action for some streams.



        You can use a collect operation that doesn’t allow to take short-cuts, e.g.



        long count = stream.collect(
        Collectors.mapping(s -> { action.accept(s); return s; }, Collectors.counting()));


        or



        long count = stream.collect(Collectors.summingLong(s -> { action.accept(s); return 1; }));





        share|improve this answer























          up vote
          6
          down vote



          accepted







          up vote
          6
          down vote



          accepted






          It might be tempting to use



          long count = stream.peek(action).count();


          and it may appear to work. However, peek’s action will only be performed when an element is being processed, but for some streams, the count may be available without processing the elements. Java 9 is going to take this opportunity, which makes the code above fail to perform action for some streams.



          You can use a collect operation that doesn’t allow to take short-cuts, e.g.



          long count = stream.collect(
          Collectors.mapping(s -> { action.accept(s); return s; }, Collectors.counting()));


          or



          long count = stream.collect(Collectors.summingLong(s -> { action.accept(s); return 1; }));





          share|improve this answer












          It might be tempting to use



          long count = stream.peek(action).count();


          and it may appear to work. However, peek’s action will only be performed when an element is being processed, but for some streams, the count may be available without processing the elements. Java 9 is going to take this opportunity, which makes the code above fail to perform action for some streams.



          You can use a collect operation that doesn’t allow to take short-cuts, e.g.



          long count = stream.collect(
          Collectors.mapping(s -> { action.accept(s); return s; }, Collectors.counting()));


          or



          long count = stream.collect(Collectors.summingLong(s -> { action.accept(s); return 1; }));






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Feb 2 '17 at 11:37









          Holger

          159k23220422




          159k23220422
























              up vote
              2
              down vote













              I would go with a reduce operation of some sort, something like this:



               int howMany = Stream.of("a", "vc", "ads", "ts", "ta").reduce(0, (i, string) -> {
              if (string.contains("a")) {
              // process a in any other way
              return i+1;
              }
              return i;
              }, (left, right) -> null); // override if parallel stream required

              System.out.println(howMany);





              share|improve this answer



















              • 2




                The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
                – Holger
                Feb 2 '17 at 12:01















              up vote
              2
              down vote













              I would go with a reduce operation of some sort, something like this:



               int howMany = Stream.of("a", "vc", "ads", "ts", "ta").reduce(0, (i, string) -> {
              if (string.contains("a")) {
              // process a in any other way
              return i+1;
              }
              return i;
              }, (left, right) -> null); // override if parallel stream required

              System.out.println(howMany);





              share|improve this answer



















              • 2




                The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
                – Holger
                Feb 2 '17 at 12:01













              up vote
              2
              down vote










              up vote
              2
              down vote









              I would go with a reduce operation of some sort, something like this:



               int howMany = Stream.of("a", "vc", "ads", "ts", "ta").reduce(0, (i, string) -> {
              if (string.contains("a")) {
              // process a in any other way
              return i+1;
              }
              return i;
              }, (left, right) -> null); // override if parallel stream required

              System.out.println(howMany);





              share|improve this answer














              I would go with a reduce operation of some sort, something like this:



               int howMany = Stream.of("a", "vc", "ads", "ts", "ta").reduce(0, (i, string) -> {
              if (string.contains("a")) {
              // process a in any other way
              return i+1;
              }
              return i;
              }, (left, right) -> null); // override if parallel stream required

              System.out.println(howMany);






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Feb 2 '17 at 11:12

























              answered Feb 2 '17 at 8:43









              Eugene

              66.5k996159




              66.5k996159








              • 2




                The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
                – Holger
                Feb 2 '17 at 12:01














              • 2




                The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
                – Holger
                Feb 2 '17 at 12:01








              2




              2




              The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
              – Holger
              Feb 2 '17 at 12:01




              The question doesn’t mention conditional processing, but if this is intended, a filter before counting would do. Besides—what’s stopping you from specifying the straight-forward merging function (left, right) -> left+right rather than (left, right) -> null? It doesn’t create any harm for sequential streams…
              – Holger
              Feb 2 '17 at 12:01










              up vote
              0
              down vote













              This can be done with peek function, as it returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.



              AtomicInteger counter = new AtomicInteger(0);

              elements
              .stream()
              .forEach(doSomething())
              .peek(elem -> counter.incrementAndGet());

              int elementsProcessed = counter.get();





              share|improve this answer

















              • 3




                and not mutate a variable outside the lambda
                – Eugene
                Feb 2 '17 at 8:47






              • 4




                Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
                – Holger
                Feb 2 '17 at 11:38










              • forEach returns void and the suggested code doesn't compile.
                – Gabriel C
                Feb 2 '17 at 23:08















              up vote
              0
              down vote













              This can be done with peek function, as it returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.



              AtomicInteger counter = new AtomicInteger(0);

              elements
              .stream()
              .forEach(doSomething())
              .peek(elem -> counter.incrementAndGet());

              int elementsProcessed = counter.get();





              share|improve this answer

















              • 3




                and not mutate a variable outside the lambda
                – Eugene
                Feb 2 '17 at 8:47






              • 4




                Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
                – Holger
                Feb 2 '17 at 11:38










              • forEach returns void and the suggested code doesn't compile.
                – Gabriel C
                Feb 2 '17 at 23:08













              up vote
              0
              down vote










              up vote
              0
              down vote









              This can be done with peek function, as it returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.



              AtomicInteger counter = new AtomicInteger(0);

              elements
              .stream()
              .forEach(doSomething())
              .peek(elem -> counter.incrementAndGet());

              int elementsProcessed = counter.get();





              share|improve this answer












              This can be done with peek function, as it returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.



              AtomicInteger counter = new AtomicInteger(0);

              elements
              .stream()
              .forEach(doSomething())
              .peek(elem -> counter.incrementAndGet());

              int elementsProcessed = counter.get();






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Feb 2 '17 at 8:44









              m4tt

              944




              944








              • 3




                and not mutate a variable outside the lambda
                – Eugene
                Feb 2 '17 at 8:47






              • 4




                Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
                – Holger
                Feb 2 '17 at 11:38










              • forEach returns void and the suggested code doesn't compile.
                – Gabriel C
                Feb 2 '17 at 23:08














              • 3




                and not mutate a variable outside the lambda
                – Eugene
                Feb 2 '17 at 8:47






              • 4




                Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
                – Holger
                Feb 2 '17 at 11:38










              • forEach returns void and the suggested code doesn't compile.
                – Gabriel C
                Feb 2 '17 at 23:08








              3




              3




              and not mutate a variable outside the lambda
              – Eugene
              Feb 2 '17 at 8:47




              and not mutate a variable outside the lambda
              – Eugene
              Feb 2 '17 at 8:47




              4




              4




              Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
              – Holger
              Feb 2 '17 at 11:38




              Besides the fact that using peek for this purpose is not recommended, it doesn’t even compile, if you try to chain a peek after the terminal forEach operation.
              – Holger
              Feb 2 '17 at 11:38












              forEach returns void and the suggested code doesn't compile.
              – Gabriel C
              Feb 2 '17 at 23:08




              forEach returns void and the suggested code doesn't compile.
              – Gabriel C
              Feb 2 '17 at 23:08










              up vote
              0
              down vote













              Streams are lazily evaluated and therefore processed in a single step, combining all intermediate operations when a final operation is called, no matter how many operations you perform over them.



              This way, you don't have to worry because your stream will be processed at once. But the best way to perform some operation on each stream's element and count the number of elements processed depends on your goal.
              Anyway, the two examples below don't mutate a variable to perform that count.



              Both examples create a Stream of Strings, perform a trim() on each String to remove blank spaces and then, filter the Strings that have some content.



              Example 1



              Uses the peek method to perform some operation over each filtered string. In this case, just print each one. Finally, it just uses the count() to get how many Strings were processed.



              Stream<String> stream = 
              Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
              long count = stream
              .map(String::trim)
              .filter(s -> !s.isEmpty())
              .peek(System.out::println)
              .count();

              System.out.printf(
              "nNumber of non-empty strings after a trim() operation: %dnn", count);


              Example 2



              Uses the collect method after filtering and mapping to get all the processed Strings into a List. By this way, the List can be printed separately and the number of elements got from list.size()



              Stream<String> stream = 
              Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
              List<String> list = stream
              .map(String::trim)
              .filter(s -> !s.isEmpty())
              .collect(Collectors.toList());

              list.forEach(System.out::println);
              System.out.printf(
              "nNumber of non-empty strings after a trim() operation: %dnn", list.size());





              share|improve this answer



























                up vote
                0
                down vote













                Streams are lazily evaluated and therefore processed in a single step, combining all intermediate operations when a final operation is called, no matter how many operations you perform over them.



                This way, you don't have to worry because your stream will be processed at once. But the best way to perform some operation on each stream's element and count the number of elements processed depends on your goal.
                Anyway, the two examples below don't mutate a variable to perform that count.



                Both examples create a Stream of Strings, perform a trim() on each String to remove blank spaces and then, filter the Strings that have some content.



                Example 1



                Uses the peek method to perform some operation over each filtered string. In this case, just print each one. Finally, it just uses the count() to get how many Strings were processed.



                Stream<String> stream = 
                Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
                long count = stream
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .peek(System.out::println)
                .count();

                System.out.printf(
                "nNumber of non-empty strings after a trim() operation: %dnn", count);


                Example 2



                Uses the collect method after filtering and mapping to get all the processed Strings into a List. By this way, the List can be printed separately and the number of elements got from list.size()



                Stream<String> stream = 
                Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
                List<String> list = stream
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toList());

                list.forEach(System.out::println);
                System.out.printf(
                "nNumber of non-empty strings after a trim() operation: %dnn", list.size());





                share|improve this answer

























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  Streams are lazily evaluated and therefore processed in a single step, combining all intermediate operations when a final operation is called, no matter how many operations you perform over them.



                  This way, you don't have to worry because your stream will be processed at once. But the best way to perform some operation on each stream's element and count the number of elements processed depends on your goal.
                  Anyway, the two examples below don't mutate a variable to perform that count.



                  Both examples create a Stream of Strings, perform a trim() on each String to remove blank spaces and then, filter the Strings that have some content.



                  Example 1



                  Uses the peek method to perform some operation over each filtered string. In this case, just print each one. Finally, it just uses the count() to get how many Strings were processed.



                  Stream<String> stream = 
                  Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
                  long count = stream
                  .map(String::trim)
                  .filter(s -> !s.isEmpty())
                  .peek(System.out::println)
                  .count();

                  System.out.printf(
                  "nNumber of non-empty strings after a trim() operation: %dnn", count);


                  Example 2



                  Uses the collect method after filtering and mapping to get all the processed Strings into a List. By this way, the List can be printed separately and the number of elements got from list.size()



                  Stream<String> stream = 
                  Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
                  List<String> list = stream
                  .map(String::trim)
                  .filter(s -> !s.isEmpty())
                  .collect(Collectors.toList());

                  list.forEach(System.out::println);
                  System.out.printf(
                  "nNumber of non-empty strings after a trim() operation: %dnn", list.size());





                  share|improve this answer














                  Streams are lazily evaluated and therefore processed in a single step, combining all intermediate operations when a final operation is called, no matter how many operations you perform over them.



                  This way, you don't have to worry because your stream will be processed at once. But the best way to perform some operation on each stream's element and count the number of elements processed depends on your goal.
                  Anyway, the two examples below don't mutate a variable to perform that count.



                  Both examples create a Stream of Strings, perform a trim() on each String to remove blank spaces and then, filter the Strings that have some content.



                  Example 1



                  Uses the peek method to perform some operation over each filtered string. In this case, just print each one. Finally, it just uses the count() to get how many Strings were processed.



                  Stream<String> stream = 
                  Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
                  long count = stream
                  .map(String::trim)
                  .filter(s -> !s.isEmpty())
                  .peek(System.out::println)
                  .count();

                  System.out.printf(
                  "nNumber of non-empty strings after a trim() operation: %dnn", count);


                  Example 2



                  Uses the collect method after filtering and mapping to get all the processed Strings into a List. By this way, the List can be printed separately and the number of elements got from list.size()



                  Stream<String> stream = 
                  Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
                  List<String> list = stream
                  .map(String::trim)
                  .filter(s -> !s.isEmpty())
                  .collect(Collectors.toList());

                  list.forEach(System.out::println);
                  System.out.printf(
                  "nNumber of non-empty strings after a trim() operation: %dnn", list.size());






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 10 at 23:33

























                  answered Feb 2 '17 at 14:09









                  Manoel Campos

                  14018




                  14018






























                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f41995426%2fwhat-is-the-most-elegant-way-to-run-a-lambda-for-each-element-of-a-java-8-stream%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

                      Florida Star v. B. J. F.

                      Danny Elfman

                      Lugert, Oklahoma