Non-terminal forEach() in a stream?

前端 未结 2 1737
时光取名叫无心
时光取名叫无心 2021-02-18 14:35

Sometimes when processing a Java stream() I find myself in need of a non-terminal forEach() to be used to trigger a side effect but without terminating processing.

I sus

相关标签:
2条回答
  • 2021-02-18 14:59

    No, there is not.

    peek() will only operate on all elements when forced to by a following operation. Can you predict what will be printed by this code?

    public class Test
    {
        private static final AtomicBoolean FLAG = new AtomicBoolean(false);
    
        private static void setFlagIfGreaterThanZero(int val)
        {
            if (val > 0) {
                FLAG.set(true);
            }
        }
    
        public static void main(String[] args)
        {
            FLAG.set(false);
    
            // Test 1
            IntStream.range(0, 10)
                     .peek(Test::setFlagIfGreaterThanZero)
                     .findFirst();
    
            System.out.println(FLAG.get());
            FLAG.set(false);
    
            // Test 2
            IntStream.range(0, 10)
                     .peek(Test::setFlagIfGreaterThanZero)
                     .sorted()
                     .findFirst();
    
            System.out.println(FLAG.get());
            FLAG.set(false);
    
            // Test 3
            IntStream.range(0, 10)
                     .boxed()
                     .peek(Test::setFlagIfGreaterThanZero)
                     .sorted()
                     .findFirst();
    
            System.out.println(FLAG.get());
            FLAG.set(false);
    
            // Test 4
            IntStream.range(0, 10)
                     .peek(Test::setFlagIfGreaterThanZero)
                     .filter(x -> x == 0)
                     .toArray();
    
            System.out.println(FLAG.get());
        }
    }
    

    The answer is:

    false
    false
    true
    true

    That output might be intuitive if you have a solid understanding of Java Streams, but hopefully it also indicates that it's a very bad idea to rely on peek() as a mid-stream forEach().

    map() also suffers the same issue. As far as I'm aware, there is no Stream operation that guarantees a sort of "process every element without taking shortcuts" behavior in every case independent of the prior and following operations.

    Although this can be a pain, the short-circuiting behavior of Streams is an important feature. You might find this excellent answer to be useful: https://stackoverflow.com/a/32194320/507761

    0 讨论(0)
  • 2021-02-18 15:03

    Yes there is. It is called peek() (example from the JavaDoc):

    Stream.of("one", "two", "three", "four")
         .peek(e -> System.out.println("Original value: " + e))
         .filter(e -> e.length() > 3)
         .peek(e -> System.out.println("Filtered value: " + e))
         .map(String::toUpperCase)
         .peek(e -> System.out.println("Mapped value: " + e))
         .collect(Collectors.toList());
    
    0 讨论(0)
提交回复
热议问题