Why AtomicInteger based Stream solutions are not recommended?












5















Say I have this list of fruits:-



List<String> f = Arrays.asList("Banana", "Apple", "Grape", "Orange", "Kiwi");


I need to prepend a serial number to each fruit and print it. The order of fruit or serial number does not matter. So this is a valid output:-



4. Kiwi
3. Orange
1. Grape
2. Apple
5. Banana


Solution #1



AtomicInteger number = new AtomicInteger(0);

String result = f.parallelStream()
.map(i -> String.format("%d. %s", number.incrementAndGet(), i))
.collect(Collectors.joining("n"));


Solution #2



String result = IntStream.rangeClosed(1, f.size())
.parallel()
.mapToObj(i -> String.format("%d. %s", i, f.get(i - 1)))
.collect(Collectors.joining("n"));


Question



Why is solution #1 a bad practice? I have seen at a lot of places that AtomicInteger based solutions are bad (like in this answer), specially in parallel stream processing (that's the reason I used parallel streams above, to try run into issues).



I looked at these questions/answers:-
In which cases Stream operations should be stateful?
Is use of AtomicInteger for indexing in Stream a legit way?
Java 8: Preferred way to count iterations of a lambda?



They just mention (unless I missed something) "unexpected results can occur". Like what? Can it happen in this example? If not, can you provide me an example where it can happen?



As for "no guarantees are made as to the order in which the mapper function is applied", well, that's the nature of parallel processing, so I accept it, and also, the order doesn't matter in this particular example.



AtomicInteger is thread safe, so it shouldn't be a problem in parallel processing.



Can someone provide examples in which cases there will be issues while using such a state-based solution?










share|improve this question




















  • 6





    tldr: Side-effects are "icky", even if "thread-safe". The ordering argument is very relevant in more generalized cases: eg. instead of adding integers (x + y == y + x), what if it was concatenating strings (concat(x,y) != concat(y,x))? There is much less chance to accidentally introduce such if side-effects are avoided.

    – user2864740
    Nov 16 '18 at 0:42








  • 2





    It's unclear from the docs whether statelessness is required or only recommended. I personally see no problem with #1, though I can imagine #2 performing better.

    – shmosel
    Nov 16 '18 at 0:45






  • 2





    Streams come from functional programming, where you should ideally have no side effects. Sometimes this isn't possible, but if there is a simple way to achieve the same thing without side effects you should use that.

    – Peter Lawrey
    Nov 16 '18 at 8:53






  • 4





    Well, when you are fine with a result where the numbers are neither, in order nor reflecting the source element order, the only remaining issue is that it is inefficient, compared to the recommended approach. But most other Q&As are about tasks not being fine with such a wrong order and well, when you use this pattern in these rare case where you are fine with a meaningless number, it might soon become a habit…

    – Holger
    Nov 16 '18 at 9:05
















5















Say I have this list of fruits:-



List<String> f = Arrays.asList("Banana", "Apple", "Grape", "Orange", "Kiwi");


I need to prepend a serial number to each fruit and print it. The order of fruit or serial number does not matter. So this is a valid output:-



4. Kiwi
3. Orange
1. Grape
2. Apple
5. Banana


Solution #1



AtomicInteger number = new AtomicInteger(0);

String result = f.parallelStream()
.map(i -> String.format("%d. %s", number.incrementAndGet(), i))
.collect(Collectors.joining("n"));


Solution #2



String result = IntStream.rangeClosed(1, f.size())
.parallel()
.mapToObj(i -> String.format("%d. %s", i, f.get(i - 1)))
.collect(Collectors.joining("n"));


Question



Why is solution #1 a bad practice? I have seen at a lot of places that AtomicInteger based solutions are bad (like in this answer), specially in parallel stream processing (that's the reason I used parallel streams above, to try run into issues).



I looked at these questions/answers:-
In which cases Stream operations should be stateful?
Is use of AtomicInteger for indexing in Stream a legit way?
Java 8: Preferred way to count iterations of a lambda?



They just mention (unless I missed something) "unexpected results can occur". Like what? Can it happen in this example? If not, can you provide me an example where it can happen?



As for "no guarantees are made as to the order in which the mapper function is applied", well, that's the nature of parallel processing, so I accept it, and also, the order doesn't matter in this particular example.



AtomicInteger is thread safe, so it shouldn't be a problem in parallel processing.



Can someone provide examples in which cases there will be issues while using such a state-based solution?










share|improve this question




















  • 6





    tldr: Side-effects are "icky", even if "thread-safe". The ordering argument is very relevant in more generalized cases: eg. instead of adding integers (x + y == y + x), what if it was concatenating strings (concat(x,y) != concat(y,x))? There is much less chance to accidentally introduce such if side-effects are avoided.

    – user2864740
    Nov 16 '18 at 0:42








  • 2





    It's unclear from the docs whether statelessness is required or only recommended. I personally see no problem with #1, though I can imagine #2 performing better.

    – shmosel
    Nov 16 '18 at 0:45






  • 2





    Streams come from functional programming, where you should ideally have no side effects. Sometimes this isn't possible, but if there is a simple way to achieve the same thing without side effects you should use that.

    – Peter Lawrey
    Nov 16 '18 at 8:53






  • 4





    Well, when you are fine with a result where the numbers are neither, in order nor reflecting the source element order, the only remaining issue is that it is inefficient, compared to the recommended approach. But most other Q&As are about tasks not being fine with such a wrong order and well, when you use this pattern in these rare case where you are fine with a meaningless number, it might soon become a habit…

    – Holger
    Nov 16 '18 at 9:05














5












5








5


1






Say I have this list of fruits:-



List<String> f = Arrays.asList("Banana", "Apple", "Grape", "Orange", "Kiwi");


I need to prepend a serial number to each fruit and print it. The order of fruit or serial number does not matter. So this is a valid output:-



4. Kiwi
3. Orange
1. Grape
2. Apple
5. Banana


Solution #1



AtomicInteger number = new AtomicInteger(0);

String result = f.parallelStream()
.map(i -> String.format("%d. %s", number.incrementAndGet(), i))
.collect(Collectors.joining("n"));


Solution #2



String result = IntStream.rangeClosed(1, f.size())
.parallel()
.mapToObj(i -> String.format("%d. %s", i, f.get(i - 1)))
.collect(Collectors.joining("n"));


Question



Why is solution #1 a bad practice? I have seen at a lot of places that AtomicInteger based solutions are bad (like in this answer), specially in parallel stream processing (that's the reason I used parallel streams above, to try run into issues).



I looked at these questions/answers:-
In which cases Stream operations should be stateful?
Is use of AtomicInteger for indexing in Stream a legit way?
Java 8: Preferred way to count iterations of a lambda?



They just mention (unless I missed something) "unexpected results can occur". Like what? Can it happen in this example? If not, can you provide me an example where it can happen?



As for "no guarantees are made as to the order in which the mapper function is applied", well, that's the nature of parallel processing, so I accept it, and also, the order doesn't matter in this particular example.



AtomicInteger is thread safe, so it shouldn't be a problem in parallel processing.



Can someone provide examples in which cases there will be issues while using such a state-based solution?










share|improve this question
















Say I have this list of fruits:-



List<String> f = Arrays.asList("Banana", "Apple", "Grape", "Orange", "Kiwi");


I need to prepend a serial number to each fruit and print it. The order of fruit or serial number does not matter. So this is a valid output:-



4. Kiwi
3. Orange
1. Grape
2. Apple
5. Banana


Solution #1



AtomicInteger number = new AtomicInteger(0);

String result = f.parallelStream()
.map(i -> String.format("%d. %s", number.incrementAndGet(), i))
.collect(Collectors.joining("n"));


Solution #2



String result = IntStream.rangeClosed(1, f.size())
.parallel()
.mapToObj(i -> String.format("%d. %s", i, f.get(i - 1)))
.collect(Collectors.joining("n"));


Question



Why is solution #1 a bad practice? I have seen at a lot of places that AtomicInteger based solutions are bad (like in this answer), specially in parallel stream processing (that's the reason I used parallel streams above, to try run into issues).



I looked at these questions/answers:-
In which cases Stream operations should be stateful?
Is use of AtomicInteger for indexing in Stream a legit way?
Java 8: Preferred way to count iterations of a lambda?



They just mention (unless I missed something) "unexpected results can occur". Like what? Can it happen in this example? If not, can you provide me an example where it can happen?



As for "no guarantees are made as to the order in which the mapper function is applied", well, that's the nature of parallel processing, so I accept it, and also, the order doesn't matter in this particular example.



AtomicInteger is thread safe, so it shouldn't be a problem in parallel processing.



Can someone provide examples in which cases there will be issues while using such a state-based solution?







java java-8 thread-safety java-stream atomicinteger






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 16 '18 at 5:13









Andrew Tobilko

28.3k104588




28.3k104588










asked Nov 16 '18 at 0:37









KartikKartik

4,19731537




4,19731537








  • 6





    tldr: Side-effects are "icky", even if "thread-safe". The ordering argument is very relevant in more generalized cases: eg. instead of adding integers (x + y == y + x), what if it was concatenating strings (concat(x,y) != concat(y,x))? There is much less chance to accidentally introduce such if side-effects are avoided.

    – user2864740
    Nov 16 '18 at 0:42








  • 2





    It's unclear from the docs whether statelessness is required or only recommended. I personally see no problem with #1, though I can imagine #2 performing better.

    – shmosel
    Nov 16 '18 at 0:45






  • 2





    Streams come from functional programming, where you should ideally have no side effects. Sometimes this isn't possible, but if there is a simple way to achieve the same thing without side effects you should use that.

    – Peter Lawrey
    Nov 16 '18 at 8:53






  • 4





    Well, when you are fine with a result where the numbers are neither, in order nor reflecting the source element order, the only remaining issue is that it is inefficient, compared to the recommended approach. But most other Q&As are about tasks not being fine with such a wrong order and well, when you use this pattern in these rare case where you are fine with a meaningless number, it might soon become a habit…

    – Holger
    Nov 16 '18 at 9:05














  • 6





    tldr: Side-effects are "icky", even if "thread-safe". The ordering argument is very relevant in more generalized cases: eg. instead of adding integers (x + y == y + x), what if it was concatenating strings (concat(x,y) != concat(y,x))? There is much less chance to accidentally introduce such if side-effects are avoided.

    – user2864740
    Nov 16 '18 at 0:42








  • 2





    It's unclear from the docs whether statelessness is required or only recommended. I personally see no problem with #1, though I can imagine #2 performing better.

    – shmosel
    Nov 16 '18 at 0:45






  • 2





    Streams come from functional programming, where you should ideally have no side effects. Sometimes this isn't possible, but if there is a simple way to achieve the same thing without side effects you should use that.

    – Peter Lawrey
    Nov 16 '18 at 8:53






  • 4





    Well, when you are fine with a result where the numbers are neither, in order nor reflecting the source element order, the only remaining issue is that it is inefficient, compared to the recommended approach. But most other Q&As are about tasks not being fine with such a wrong order and well, when you use this pattern in these rare case where you are fine with a meaningless number, it might soon become a habit…

    – Holger
    Nov 16 '18 at 9:05








6




6





tldr: Side-effects are "icky", even if "thread-safe". The ordering argument is very relevant in more generalized cases: eg. instead of adding integers (x + y == y + x), what if it was concatenating strings (concat(x,y) != concat(y,x))? There is much less chance to accidentally introduce such if side-effects are avoided.

– user2864740
Nov 16 '18 at 0:42







tldr: Side-effects are "icky", even if "thread-safe". The ordering argument is very relevant in more generalized cases: eg. instead of adding integers (x + y == y + x), what if it was concatenating strings (concat(x,y) != concat(y,x))? There is much less chance to accidentally introduce such if side-effects are avoided.

– user2864740
Nov 16 '18 at 0:42






2




2





It's unclear from the docs whether statelessness is required or only recommended. I personally see no problem with #1, though I can imagine #2 performing better.

– shmosel
Nov 16 '18 at 0:45





It's unclear from the docs whether statelessness is required or only recommended. I personally see no problem with #1, though I can imagine #2 performing better.

– shmosel
Nov 16 '18 at 0:45




2




2





Streams come from functional programming, where you should ideally have no side effects. Sometimes this isn't possible, but if there is a simple way to achieve the same thing without side effects you should use that.

– Peter Lawrey
Nov 16 '18 at 8:53





Streams come from functional programming, where you should ideally have no side effects. Sometimes this isn't possible, but if there is a simple way to achieve the same thing without side effects you should use that.

– Peter Lawrey
Nov 16 '18 at 8:53




4




4





Well, when you are fine with a result where the numbers are neither, in order nor reflecting the source element order, the only remaining issue is that it is inefficient, compared to the recommended approach. But most other Q&As are about tasks not being fine with such a wrong order and well, when you use this pattern in these rare case where you are fine with a meaningless number, it might soon become a habit…

– Holger
Nov 16 '18 at 9:05





Well, when you are fine with a result where the numbers are neither, in order nor reflecting the source element order, the only remaining issue is that it is inefficient, compared to the recommended approach. But most other Q&As are about tasks not being fine with such a wrong order and well, when you use this pattern in these rare case where you are fine with a meaningless number, it might soon become a habit…

– Holger
Nov 16 '18 at 9:05












3 Answers
3






active

oldest

votes


















2















Note also that attempting to access mutable state from behavioral parameters presents you with a bad choice with respect to safety and performance; if you do not synchronize access to that state, you have a data race and therefore your code is broken, but if you do synchronize access to that state, you risk having contention undermine the parallelism you are seeking to benefit from. The best approach is to avoid stateful behavioral parameters to stream operations entirely; there is usually a way to restructure the stream pipeline to avoid statefulness.



Package java.util.stream, Stateless behaviors




From the perspective of thread-safety and correctness, there is nothing wrong with solution 1. Performance (as an advantage of parallel processing) might suffer, though.






Why is solution #1 a bad practice?




I wouldn't say it's a bad practice or something unacceptable. It's simply not recommended for the sake of performance.




They just mention (unless I missed something) "unexpected results can occur". Like what?




"Unexpected results" is a very broad term, and usually refers to improper synchronisation, "What's the hell just happened?"-like behaviour.




Can it happen in this example?




It's not the case. You are likely not going to run into issues.




If not, can you provide me an example where it can happen?




Change the AtomicInteger to an int*, replace number.incrementAndGet() with ++number, and you will have one.





*a boxed int (e.g. wrapper-based, array-based) so you can work with it within a lambda






share|improve this answer

































    3














    Well look at what the answer from Stuart Marks here - he is using a stateful predicate.



    The are a couple of potential problems, but if you don't care about them or really understand them - you should be fine.



    First is order, exhibited under the current implementation for parallel processing, but if you don't care about order, like in your example, you are ok.



    Second one is potential speed AtomicInteger will be times slower to increment that a simple int, as said, if you care about this.



    Third one is more subtle. Sometimes there is no guarantee that map will be executed, at all, for example since java-9:



     someStream.map(i -> /* do something with i and numbers */)
    .count();


    The point here is that since you are counting, there is no need to do the mapping, so its skipped. In general, the elements that hit some intermediate operation are not guaranteed to get to the terminal one. Imagine a map.filter.map situation, the first map might "see" more elements compared to the second one, because some elements might be filtered. So it's not recommended to rely on this, unless you can reason exactly what is going on.



    In your example, IMO, you are more than safe to do what you do; but if you slightly change your code, this requires additional reasoning to prove it's correctness. I would go with solution 2, just because it's a lot easier to understand for me and it does not have the potential problems listed above.






    share|improve this answer

































      1














      Case 2 - In API notes of IntStream class returns a sequential ordered IntStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1 kind of for loop thus parallel stream are processing it one by one and providing the correct order.



       * @param startInclusive the (inclusive) initial value
      * @param endInclusive the inclusive upper bound
      * @return a sequential {@code IntStream} for the range of {@code int}
      * elements
      */
      public static IntStream rangeClosed(int startInclusive, int endInclusive) {


      Case 1 - It is obvious that the list will be processed in parallel thus the order will not be correct. Since mapping operation is performed in parallel, the results for the same input could vary from run to run, due to thread scheduling differences thus no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread also there is no guarantee how a mapper function is also applied to the particular elements within the stream.



      Source Java Doc






      share|improve this answer


























      • @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

        – zack
        Nov 16 '18 at 4:20











      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%2f53329809%2fwhy-atomicinteger-based-stream-solutions-are-not-recommended%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2















      Note also that attempting to access mutable state from behavioral parameters presents you with a bad choice with respect to safety and performance; if you do not synchronize access to that state, you have a data race and therefore your code is broken, but if you do synchronize access to that state, you risk having contention undermine the parallelism you are seeking to benefit from. The best approach is to avoid stateful behavioral parameters to stream operations entirely; there is usually a way to restructure the stream pipeline to avoid statefulness.



      Package java.util.stream, Stateless behaviors




      From the perspective of thread-safety and correctness, there is nothing wrong with solution 1. Performance (as an advantage of parallel processing) might suffer, though.






      Why is solution #1 a bad practice?




      I wouldn't say it's a bad practice or something unacceptable. It's simply not recommended for the sake of performance.




      They just mention (unless I missed something) "unexpected results can occur". Like what?




      "Unexpected results" is a very broad term, and usually refers to improper synchronisation, "What's the hell just happened?"-like behaviour.




      Can it happen in this example?




      It's not the case. You are likely not going to run into issues.




      If not, can you provide me an example where it can happen?




      Change the AtomicInteger to an int*, replace number.incrementAndGet() with ++number, and you will have one.





      *a boxed int (e.g. wrapper-based, array-based) so you can work with it within a lambda






      share|improve this answer






























        2















        Note also that attempting to access mutable state from behavioral parameters presents you with a bad choice with respect to safety and performance; if you do not synchronize access to that state, you have a data race and therefore your code is broken, but if you do synchronize access to that state, you risk having contention undermine the parallelism you are seeking to benefit from. The best approach is to avoid stateful behavioral parameters to stream operations entirely; there is usually a way to restructure the stream pipeline to avoid statefulness.



        Package java.util.stream, Stateless behaviors




        From the perspective of thread-safety and correctness, there is nothing wrong with solution 1. Performance (as an advantage of parallel processing) might suffer, though.






        Why is solution #1 a bad practice?




        I wouldn't say it's a bad practice or something unacceptable. It's simply not recommended for the sake of performance.




        They just mention (unless I missed something) "unexpected results can occur". Like what?




        "Unexpected results" is a very broad term, and usually refers to improper synchronisation, "What's the hell just happened?"-like behaviour.




        Can it happen in this example?




        It's not the case. You are likely not going to run into issues.




        If not, can you provide me an example where it can happen?




        Change the AtomicInteger to an int*, replace number.incrementAndGet() with ++number, and you will have one.





        *a boxed int (e.g. wrapper-based, array-based) so you can work with it within a lambda






        share|improve this answer




























          2












          2








          2








          Note also that attempting to access mutable state from behavioral parameters presents you with a bad choice with respect to safety and performance; if you do not synchronize access to that state, you have a data race and therefore your code is broken, but if you do synchronize access to that state, you risk having contention undermine the parallelism you are seeking to benefit from. The best approach is to avoid stateful behavioral parameters to stream operations entirely; there is usually a way to restructure the stream pipeline to avoid statefulness.



          Package java.util.stream, Stateless behaviors




          From the perspective of thread-safety and correctness, there is nothing wrong with solution 1. Performance (as an advantage of parallel processing) might suffer, though.






          Why is solution #1 a bad practice?




          I wouldn't say it's a bad practice or something unacceptable. It's simply not recommended for the sake of performance.




          They just mention (unless I missed something) "unexpected results can occur". Like what?




          "Unexpected results" is a very broad term, and usually refers to improper synchronisation, "What's the hell just happened?"-like behaviour.




          Can it happen in this example?




          It's not the case. You are likely not going to run into issues.




          If not, can you provide me an example where it can happen?




          Change the AtomicInteger to an int*, replace number.incrementAndGet() with ++number, and you will have one.





          *a boxed int (e.g. wrapper-based, array-based) so you can work with it within a lambda






          share|improve this answer
















          Note also that attempting to access mutable state from behavioral parameters presents you with a bad choice with respect to safety and performance; if you do not synchronize access to that state, you have a data race and therefore your code is broken, but if you do synchronize access to that state, you risk having contention undermine the parallelism you are seeking to benefit from. The best approach is to avoid stateful behavioral parameters to stream operations entirely; there is usually a way to restructure the stream pipeline to avoid statefulness.



          Package java.util.stream, Stateless behaviors




          From the perspective of thread-safety and correctness, there is nothing wrong with solution 1. Performance (as an advantage of parallel processing) might suffer, though.






          Why is solution #1 a bad practice?




          I wouldn't say it's a bad practice or something unacceptable. It's simply not recommended for the sake of performance.




          They just mention (unless I missed something) "unexpected results can occur". Like what?




          "Unexpected results" is a very broad term, and usually refers to improper synchronisation, "What's the hell just happened?"-like behaviour.




          Can it happen in this example?




          It's not the case. You are likely not going to run into issues.




          If not, can you provide me an example where it can happen?




          Change the AtomicInteger to an int*, replace number.incrementAndGet() with ++number, and you will have one.





          *a boxed int (e.g. wrapper-based, array-based) so you can work with it within a lambda







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 16 '18 at 19:03

























          answered Nov 16 '18 at 5:33









          Andrew TobilkoAndrew Tobilko

          28.3k104588




          28.3k104588

























              3














              Well look at what the answer from Stuart Marks here - he is using a stateful predicate.



              The are a couple of potential problems, but if you don't care about them or really understand them - you should be fine.



              First is order, exhibited under the current implementation for parallel processing, but if you don't care about order, like in your example, you are ok.



              Second one is potential speed AtomicInteger will be times slower to increment that a simple int, as said, if you care about this.



              Third one is more subtle. Sometimes there is no guarantee that map will be executed, at all, for example since java-9:



               someStream.map(i -> /* do something with i and numbers */)
              .count();


              The point here is that since you are counting, there is no need to do the mapping, so its skipped. In general, the elements that hit some intermediate operation are not guaranteed to get to the terminal one. Imagine a map.filter.map situation, the first map might "see" more elements compared to the second one, because some elements might be filtered. So it's not recommended to rely on this, unless you can reason exactly what is going on.



              In your example, IMO, you are more than safe to do what you do; but if you slightly change your code, this requires additional reasoning to prove it's correctness. I would go with solution 2, just because it's a lot easier to understand for me and it does not have the potential problems listed above.






              share|improve this answer






























                3














                Well look at what the answer from Stuart Marks here - he is using a stateful predicate.



                The are a couple of potential problems, but if you don't care about them or really understand them - you should be fine.



                First is order, exhibited under the current implementation for parallel processing, but if you don't care about order, like in your example, you are ok.



                Second one is potential speed AtomicInteger will be times slower to increment that a simple int, as said, if you care about this.



                Third one is more subtle. Sometimes there is no guarantee that map will be executed, at all, for example since java-9:



                 someStream.map(i -> /* do something with i and numbers */)
                .count();


                The point here is that since you are counting, there is no need to do the mapping, so its skipped. In general, the elements that hit some intermediate operation are not guaranteed to get to the terminal one. Imagine a map.filter.map situation, the first map might "see" more elements compared to the second one, because some elements might be filtered. So it's not recommended to rely on this, unless you can reason exactly what is going on.



                In your example, IMO, you are more than safe to do what you do; but if you slightly change your code, this requires additional reasoning to prove it's correctness. I would go with solution 2, just because it's a lot easier to understand for me and it does not have the potential problems listed above.






                share|improve this answer




























                  3












                  3








                  3







                  Well look at what the answer from Stuart Marks here - he is using a stateful predicate.



                  The are a couple of potential problems, but if you don't care about them or really understand them - you should be fine.



                  First is order, exhibited under the current implementation for parallel processing, but if you don't care about order, like in your example, you are ok.



                  Second one is potential speed AtomicInteger will be times slower to increment that a simple int, as said, if you care about this.



                  Third one is more subtle. Sometimes there is no guarantee that map will be executed, at all, for example since java-9:



                   someStream.map(i -> /* do something with i and numbers */)
                  .count();


                  The point here is that since you are counting, there is no need to do the mapping, so its skipped. In general, the elements that hit some intermediate operation are not guaranteed to get to the terminal one. Imagine a map.filter.map situation, the first map might "see" more elements compared to the second one, because some elements might be filtered. So it's not recommended to rely on this, unless you can reason exactly what is going on.



                  In your example, IMO, you are more than safe to do what you do; but if you slightly change your code, this requires additional reasoning to prove it's correctness. I would go with solution 2, just because it's a lot easier to understand for me and it does not have the potential problems listed above.






                  share|improve this answer















                  Well look at what the answer from Stuart Marks here - he is using a stateful predicate.



                  The are a couple of potential problems, but if you don't care about them or really understand them - you should be fine.



                  First is order, exhibited under the current implementation for parallel processing, but if you don't care about order, like in your example, you are ok.



                  Second one is potential speed AtomicInteger will be times slower to increment that a simple int, as said, if you care about this.



                  Third one is more subtle. Sometimes there is no guarantee that map will be executed, at all, for example since java-9:



                   someStream.map(i -> /* do something with i and numbers */)
                  .count();


                  The point here is that since you are counting, there is no need to do the mapping, so its skipped. In general, the elements that hit some intermediate operation are not guaranteed to get to the terminal one. Imagine a map.filter.map situation, the first map might "see" more elements compared to the second one, because some elements might be filtered. So it's not recommended to rely on this, unless you can reason exactly what is going on.



                  In your example, IMO, you are more than safe to do what you do; but if you slightly change your code, this requires additional reasoning to prove it's correctness. I would go with solution 2, just because it's a lot easier to understand for me and it does not have the potential problems listed above.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 16 '18 at 5:16









                  Andrew Tobilko

                  28.3k104588




                  28.3k104588










                  answered Nov 16 '18 at 4:50









                  EugeneEugene

                  71.4k9103171




                  71.4k9103171























                      1














                      Case 2 - In API notes of IntStream class returns a sequential ordered IntStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1 kind of for loop thus parallel stream are processing it one by one and providing the correct order.



                       * @param startInclusive the (inclusive) initial value
                      * @param endInclusive the inclusive upper bound
                      * @return a sequential {@code IntStream} for the range of {@code int}
                      * elements
                      */
                      public static IntStream rangeClosed(int startInclusive, int endInclusive) {


                      Case 1 - It is obvious that the list will be processed in parallel thus the order will not be correct. Since mapping operation is performed in parallel, the results for the same input could vary from run to run, due to thread scheduling differences thus no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread also there is no guarantee how a mapper function is also applied to the particular elements within the stream.



                      Source Java Doc






                      share|improve this answer


























                      • @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

                        – zack
                        Nov 16 '18 at 4:20
















                      1














                      Case 2 - In API notes of IntStream class returns a sequential ordered IntStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1 kind of for loop thus parallel stream are processing it one by one and providing the correct order.



                       * @param startInclusive the (inclusive) initial value
                      * @param endInclusive the inclusive upper bound
                      * @return a sequential {@code IntStream} for the range of {@code int}
                      * elements
                      */
                      public static IntStream rangeClosed(int startInclusive, int endInclusive) {


                      Case 1 - It is obvious that the list will be processed in parallel thus the order will not be correct. Since mapping operation is performed in parallel, the results for the same input could vary from run to run, due to thread scheduling differences thus no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread also there is no guarantee how a mapper function is also applied to the particular elements within the stream.



                      Source Java Doc






                      share|improve this answer


























                      • @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

                        – zack
                        Nov 16 '18 at 4:20














                      1












                      1








                      1







                      Case 2 - In API notes of IntStream class returns a sequential ordered IntStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1 kind of for loop thus parallel stream are processing it one by one and providing the correct order.



                       * @param startInclusive the (inclusive) initial value
                      * @param endInclusive the inclusive upper bound
                      * @return a sequential {@code IntStream} for the range of {@code int}
                      * elements
                      */
                      public static IntStream rangeClosed(int startInclusive, int endInclusive) {


                      Case 1 - It is obvious that the list will be processed in parallel thus the order will not be correct. Since mapping operation is performed in parallel, the results for the same input could vary from run to run, due to thread scheduling differences thus no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread also there is no guarantee how a mapper function is also applied to the particular elements within the stream.



                      Source Java Doc






                      share|improve this answer















                      Case 2 - In API notes of IntStream class returns a sequential ordered IntStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1 kind of for loop thus parallel stream are processing it one by one and providing the correct order.



                       * @param startInclusive the (inclusive) initial value
                      * @param endInclusive the inclusive upper bound
                      * @return a sequential {@code IntStream} for the range of {@code int}
                      * elements
                      */
                      public static IntStream rangeClosed(int startInclusive, int endInclusive) {


                      Case 1 - It is obvious that the list will be processed in parallel thus the order will not be correct. Since mapping operation is performed in parallel, the results for the same input could vary from run to run, due to thread scheduling differences thus no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread also there is no guarantee how a mapper function is also applied to the particular elements within the stream.



                      Source Java Doc







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Nov 16 '18 at 4:56

























                      answered Nov 16 '18 at 3:49









                      zackzack

                      868




                      868













                      • @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

                        – zack
                        Nov 16 '18 at 4:20



















                      • @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

                        – zack
                        Nov 16 '18 at 4:20

















                      @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

                      – zack
                      Nov 16 '18 at 4:20





                      @Kartik: There is no guarantees that different operations on the "same" element within the same stream pipeline are executed in the same thread. So there is no guarantee how a mapper function is also applied to the particular elements within the stream or in what thread any behavioral parameter is executed.Thus result might be unexpected as well.

                      – zack
                      Nov 16 '18 at 4:20


















                      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%2f53329809%2fwhy-atomicinteger-based-stream-solutions-are-not-recommended%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

                      Xamarin.iOS Cant Deploy on Iphone

                      Glorious Revolution

                      Dulmage-Mendelsohn matrix decomposition in Python