Can I duplicate a Stream in Java 8?

后端 未结 8 2168
别跟我提以往
别跟我提以往 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:12

    It's possible if you're buffering elements that you've consumed in one duplicate, but not in the other yet.

    We've implemented a duplicate() method for streams in jOOλ, an Open Source library that we created to improve integration testing for jOOQ. Essentially, you can just write:

    Tuple2, Seq> desired_streams = Seq.seq(
        IntStream.range(1, 100).filter(n -> n % 2 == 0).boxed()
    ).duplicate();
    

    (note: we currently need to box the stream, as we haven't implemented an IntSeq yet)

    Internally, there is a LinkedList buffer storing all values that have been consumed from one stream but not from the other. That's probably as efficient as it gets if your two streams are consumed about at the same rate.

    Here's how the algorithm works:

    static  Tuple2, Seq> duplicate(Stream stream) {
        final LinkedList gap = new LinkedList<>();
        final Iterator it = stream.iterator();
    
        @SuppressWarnings("unchecked")
        final Iterator[] ahead = new Iterator[] { null };
    
        class Duplicate implements Iterator {
            @Override
            public boolean hasNext() {
                if (ahead[0] == null || ahead[0] == this)
                    return it.hasNext();
    
                return !gap.isEmpty();
            }
    
            @Override
            public T next() {
                if (ahead[0] == null)
                    ahead[0] = this;
    
                if (ahead[0] == this) {
                    T value = it.next();
                    gap.offer(value);
                    return value;
                }
    
                return gap.poll();
            }
        }
    
        return tuple(seq(new Duplicate()), seq(new Duplicate()));
    }
    

    More source code here

    In fact, using jOOλ, you'll be able to write a complete one-liner like so:

    Tuple2, Seq> desired_streams = Seq.seq(
        IntStream.range(1, 100).filter(n -> n % 2 == 0).boxed()
    ).duplicate()
     .map1(s -> s.filter(n -> n % 7 == 0))
     .map2(s -> s.filter(n -> n % 5 == 0));
    
    // This will yield 14, 28, 42, 56...
    desired_streams.v1.forEach(System.out::println)
    
    // This will yield 10, 20, 30, 40...
    desired_streams.v2.forEach(System.out::println);
    

提交回复
热议问题