从Java 8流中获取下一个项目
我想从Java 8 Stream
检索并删除下一个项目,而不会关闭此Stream
。
Stream integerStream = Stream.iterate( 0, x -> new Integer(x + 1) ); Integer zero = integerStream.getNext(); // 0 Integer one = integerStream.getNext(); // 1 ...
这可能吗?
是的,有一种方法可以做到这一点,但有一些限制。
Stream infiniteStream = Stream.iterate( 0, x -> new Integer(x + 1) ); Iterator iter = infiniteStream.iterator(); Integer zero = iter.next(); Integer one = iter.next();
或者,
Stream infiniteStream = Stream.iterate( 0, x -> new Integer(x + 1) ); Spliterator spliterator = infiniteStream.spliterator(); spliterator.tryAdvance(i -> System.out.println(i)); // zero spliterator.tryAdvance(i -> System.out.println(i)); // one
给定一个Stream
,可以从中获取Iterator
或Spliterator
,或查询它是否是并行流等。这些是在BaseStream
接口上定义的,这是Stream
的BaseStream
接口,这使得它们很容易被遗漏。
在这种情况下,我们知道流是无限的,因此不需要调用Iterator的hasNext()
方法或检查Spliterator的tryAdvance()
的返回值
限制是Stream
的iterator()
和spliterator()
方法都是终端操作 ,这意味着在调用它们之后,返回的Iterator或Spliterator可以独占访问Stream表示的值。 不允许对流进行进一步操作(例如filter
或map
等),并且将遇到IllegalStateException
。
如果你想剥离前几个元素然后恢复流处理,你可以将分裂器重新转换为如下所示的流:
Stream stream2 = StreamSupport.stream(spliterator, false);
对于某些事情,这可能会很好,但我不确定我会推荐这种技术。 我认为它会在生成下一个元素的路径中添加一些额外的对象,从而增加额外的方法调用。
编辑评论(与您的问题无关):
- 不要使用
new Integer(val)
。 而是使用Integer.valueOf(val)
,如果它可用,它将重用盒装整数,对于-128到127范围内的值通常是正确的。 - 您可以使用
IntStream
而不是Stream
来完全避免装箱开销。 它没有完整的流操作,但它确实有iterate()
,它接受一个对原始int
值进行操作的函数。
根据Stuart的回答和Iterator-to-Stream转换 ,我提出了以下快速而肮脏的包装器类。 它没有经过测试,并且它不是线程安全的,但它为我提供了我目前需要的东西 – 删除和使用单个项目,同时保持此流“开放”。
PeelingStream
提供了一个方法T getNext()
来屏蔽someWrappedStream.iterator()
的终端流操作语义:
public class PeelingStream implements Stream { private Stream wrapped; public PeelingStream(Stream toBeWrapped) { this.wrapped = toBeWrapped; } public T getNext() { Iterator iterator = wrapped.iterator(); T next = iterator.next(); Iterable remainingIterable = () -> iterator; wrapped = StreamSupport.stream(remainingIterable.spliterator(), false); return next; } ///////////////////// from here, only plain delegate methods public Iterator iterator() { return wrapped.iterator(); } public Spliterator spliterator() { return wrapped.spliterator(); } public boolean isParallel() { return wrapped.isParallel(); } public Stream sequential() { return wrapped.sequential(); } public Stream parallel() { return wrapped.parallel(); } public Stream unordered() { return wrapped.unordered(); } public Stream onClose(Runnable closeHandler) { return wrapped.onClose(closeHandler); } public void close() { wrapped.close(); } public Stream filter(Predicate super T> predicate) { return wrapped.filter(predicate); } public Stream map(Function super T, ? extends R> mapper) { return wrapped.map(mapper); } public IntStream mapToInt(ToIntFunction super T> mapper) { return wrapped.mapToInt(mapper); } public LongStream mapToLong(ToLongFunction super T> mapper) { return wrapped.mapToLong(mapper); } public DoubleStream mapToDouble(ToDoubleFunction super T> mapper) { return wrapped.mapToDouble(mapper); } public Stream flatMap( Function super T, ? extends Stream extends R>> mapper) { return wrapped.flatMap(mapper); } public IntStream flatMapToInt( Function super T, ? extends IntStream> mapper) { return wrapped.flatMapToInt(mapper); } public LongStream flatMapToLong( Function super T, ? extends LongStream> mapper) { return wrapped.flatMapToLong(mapper); } public DoubleStream flatMapToDouble( Function super T, ? extends DoubleStream> mapper) { return wrapped.flatMapToDouble(mapper); } public Stream distinct() { return wrapped.distinct(); } public Stream sorted() { return wrapped.sorted(); } public Stream sorted(Comparator super T> comparator) { return wrapped.sorted(comparator); } public Stream peek(Consumer super T> action) { return wrapped.peek(action); } public Stream limit(long maxSize) { return wrapped.limit(maxSize); } public Stream skip(long n) { return wrapped.skip(n); } public void forEach(Consumer super T> action) { wrapped.forEach(action); } public void forEachOrdered(Consumer super T> action) { wrapped.forEachOrdered(action); } public Object[] toArray() { return wrapped.toArray(); } public A[] toArray(IntFunction generator) { return wrapped.toArray(generator); } public T reduce(T identity, BinaryOperator accumulator) { return wrapped.reduce(identity, accumulator); } public Optional reduce(BinaryOperator accumulator) { return wrapped.reduce(accumulator); } public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { return wrapped.reduce(identity, accumulator, combiner); } public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { return wrapped.collect(supplier, accumulator, combiner); } public R collect(Collector super T, A, R> collector) { return wrapped.collect(collector); } public Optional min(Comparator super T> comparator) { return wrapped.min(comparator); } public Optional max(Comparator super T> comparator) { return wrapped.max(comparator); } public long count() { return wrapped.count(); } public boolean anyMatch(Predicate super T> predicate) { return wrapped.anyMatch(predicate); } public boolean allMatch(Predicate super T> predicate) { return wrapped.allMatch(predicate); } public boolean noneMatch(Predicate super T> predicate) { return wrapped.noneMatch(predicate); } public Optional findFirst() { return wrapped.findFirst(); } public Optional findAny() { return wrapped.findAny(); } }
一个小测试:
@Test public void testPeelingOffItemsFromStream() { Stream infiniteStream = Stream.iterate(0, x -> x + 1); PeelingStream peelingInfiniteStream = new PeelingStream<>(infiniteStream); Integer one = peelingInfiniteStream.getNext(); assertThat(one, equalTo(0)); Integer two = peelingInfiniteStream.getNext(); assertThat(two, equalTo(1)); Stream limitedStream = peelingInfiniteStream.limit(3); // 2 3 4 int sumOf234 = limitedStream.mapToInt(x -> x.intValue()).sum(); assertThat(sumOf234, equalTo(2 + 3 + 4)); }