Can I duplicate a Stream in Java 8?

后端 未结 8 2154
别跟我提以往
别跟我提以往 2020-12-08 04:03

Sometimes I want to perform a set of operations on a stream, and then process the resulting stream two different ways with other operations.

Can I do this without ha

8条回答
  •  北海茫月
    2020-12-08 04:21

    Update: This doesn't work. See explanation below, after the text of the original answer.

    How silly of me. All that I need to do is:

    Stream desired_stream = IntStream.range(1, 100).filter(n -> n % 2 == 0);
    Stream stream14 = desired_stream.filter(n -> n % 7 == 0); // multiples of 14
    Stream stream10 = desired_stream.filter(n -> n % 5 == 0); // multiples of 10
    

    Explanation why this does not work:

    If you code it up and try to collect both streams, the first one will collect fine, but trying to stream the second one will throw the exception: java.lang.IllegalStateException: stream has already been operated upon or closed.

    To elaborate, streams are stateful objects (which by the way cannot be reset or rewound). You can think of them as iterators, which in turn are like pointers. So stream14 and stream10 can be thought of as references to the same pointer. Consuming the first stream all the way will cause the pointer to go "past the end." Trying to consume the second stream is like trying to access a pointer that is already "past the end," Which naturally is an illegal operation.

    As the accepted answer shows, the code to create the stream must be executed twice but it can be compartmentalized into a Supplier lambda or a similar construct.

    Full test code: save into Foo.java, then javac Foo.java, then java Foo

    import java.util.stream.IntStream;
    
    public class Foo {
      public static void main (String [] args) {
        IntStream s = IntStream.range(0, 100).filter(n -> n % 2 == 0);
        IntStream s1 = s.filter(n -> n % 5 == 0);
        s1.forEach(n -> System.out.println(n));
        IntStream s2 = s.filter(n -> n % 7 == 0);
        s2.forEach(n -> System.out.println(n));
      }
    }
    

    Output:

    $ javac Foo.java
    $ java Foo
    0
    10
    20
    30
    40
    50
    60
    70
    80
    90
    Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
        at java.util.stream.AbstractPipeline.(AbstractPipeline.java:203)
        at java.util.stream.IntPipeline.(IntPipeline.java:91)
        at java.util.stream.IntPipeline$StatelessOp.(IntPipeline.java:592)
        at java.util.stream.IntPipeline$9.(IntPipeline.java:332)
        at java.util.stream.IntPipeline.filter(IntPipeline.java:331)
        at Foo.main(Foo.java:8)
    

提交回复
热议问题