2014-10-27 120 views
7

我想檢索並從Java 8 Stream中刪除下一個項目,但未關閉此Stream從Java 8流獲取下一個項目

Stream<Integer> integerStream = Stream.iterate(0, x -> new Integer(x + 1)); 
Integer zero = integerStream.getNext(); // 0 
Integer one = integerStream.getNext(); // 1 
... 

這可能嗎?

+1

您是否在考慮實際使用的刪除的項目,或丟棄它們?對於後者,'.skip(n)'是實現它的方法。 – 2014-10-27 20:57:29

回答

1

根據Stuart's answerIterator-to-Stream conversion,我想出了下面的快速和骯髒的包裝類。它沒有經過測試,也不是線程安全的,但它提供了我目前需要的內容,並且保留這個流「打開」。

PeelingStream<T>提供了一種方法T getNext()遮蔽掉someWrappedStream.iterator()終端流操作語義:

public class PeelingStream<T> implements Stream<T> { 

    private Stream<T> wrapped; 

    public PeelingStream(Stream<T> toBeWrapped) { 
     this.wrapped = toBeWrapped; 
    } 

    public T getNext() { 
     Iterator<T> iterator = wrapped.iterator(); 
     T next = iterator.next(); 
     Iterable<T> remainingIterable =() -> iterator; 
     wrapped = StreamSupport.stream(remainingIterable.spliterator(), 
       false); 

     return next; 
    } 

    ///////////////////// from here, only plain delegate methods 

    public Iterator<T> iterator() { 
     return wrapped.iterator(); 
    } 

    public Spliterator<T> spliterator() { 
     return wrapped.spliterator(); 
    } 

    public boolean isParallel() { 
     return wrapped.isParallel(); 
    } 

    public Stream<T> sequential() { 
     return wrapped.sequential(); 
    } 

    public Stream<T> parallel() { 
     return wrapped.parallel(); 
    } 

    public Stream<T> unordered() { 
     return wrapped.unordered(); 
    } 

    public Stream<T> onClose(Runnable closeHandler) { 
     return wrapped.onClose(closeHandler); 

    } 

    public void close() { 
     wrapped.close(); 
    } 

    public Stream<T> filter(Predicate<? super T> predicate) { 
     return wrapped.filter(predicate); 
    } 

    public <R> Stream<R> 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 <R> Stream<R> 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<T> distinct() { 
     return wrapped.distinct(); 
    } 

    public Stream<T> sorted() { 
     return wrapped.sorted(); 
    } 

    public Stream<T> sorted(Comparator<? super T> comparator) { 
     return wrapped.sorted(comparator); 
    } 

    public Stream<T> peek(Consumer<? super T> action) { 
     return wrapped.peek(action); 
    } 

    public Stream<T> limit(long maxSize) { 
     return wrapped.limit(maxSize); 
    } 

    public Stream<T> 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> A[] toArray(IntFunction<A[]> generator) { 
     return wrapped.toArray(generator); 
    } 

    public T reduce(T identity, BinaryOperator<T> accumulator) { 
     return wrapped.reduce(identity, accumulator); 
    } 

    public Optional<T> reduce(BinaryOperator<T> accumulator) { 
     return wrapped.reduce(accumulator); 
    } 

    public <U> U reduce(U identity, 
      BiFunction<U, ? super T, U> accumulator, 
      BinaryOperator<U> combiner) { 
     return wrapped.reduce(identity, accumulator, combiner); 
    } 

    public <R> R collect(Supplier<R> supplier, 
      BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) { 
     return wrapped.collect(supplier, accumulator, combiner); 
    } 

    public <R, A> R collect(Collector<? super T, A, R> collector) { 
     return wrapped.collect(collector); 
    } 

    public Optional<T> min(Comparator<? super T> comparator) { 
     return wrapped.min(comparator); 
    } 

    public Optional<T> 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<T> findFirst() { 
     return wrapped.findFirst(); 
    } 

    public Optional<T> findAny() { 
     return wrapped.findAny(); 
    } 

} 

一個小測試:

@Test 
public void testPeelingOffItemsFromStream() { 

    Stream<Integer> infiniteStream = Stream.iterate(0, x -> x + 1); 

    PeelingStream<Integer> peelingInfiniteStream = new PeelingStream<>(infiniteStream); 

    Integer one = peelingInfiniteStream.getNext(); 
    assertThat(one, equalTo(0)); 

    Integer two = peelingInfiniteStream.getNext(); 
    assertThat(two, equalTo(1)); 

    Stream<Integer> limitedStream = peelingInfiniteStream.limit(3); // 2 3 4 
    int sumOf234 = limitedStream.mapToInt(x -> x.intValue()).sum(); 
    assertThat(sumOf234, equalTo(2 + 3 + 4)); 

} 
13

是的,有一種方法可以做到這一點,但有一些限制。

Stream<Integer> infiniteStream = Stream.iterate(0, x -> new Integer(x + 1)); 
Iterator<Integer> iter = infiniteStream.iterator(); 
Integer zero = iter.next(); 
Integer one = iter.next(); 

或者,

Stream<Integer> infiniteStream = Stream.iterate(0, x -> new Integer(x + 1)); 
Spliterator<Integer> spliterator = infiniteStream.spliterator(); 
spliterator.tryAdvance(i -> System.out.println(i)); // zero 
spliterator.tryAdvance(i -> System.out.println(i)); // one 

給定一個Stream,有可能從它得到一個IteratorSpliterator,或者查詢它是否是一個平行流等,這些是本BaseStream接口上定義, Stream超級界面,這使他們有點容易錯過。

在這種情況下,我們知道流是無限的,所以沒有必要調用迭代器的hasNext()方法或檢查Spliterator的tryAdvance()

限制的返回值是兩者的iterator()spliterator()方法Stream終端操作這意味着在它們被調用之後,返回的迭代器或Spliterator可獨佔訪問Stream所表示的值。此流上的其他操作(例如filtermap等等)是不允許的,將會遇到IllegalStateException

如果你想剝離第一對夫婦的元素,然後重新開始流處理,你可以把一個spliterator迴流,像這樣:

Stream<Integer> stream2 = StreamSupport.stream(spliterator, false); 

這可能會爲一些事情做工精細,但我我不確定我會推薦這種技術。我認爲它增加了一些額外的對象,因此在生成下一個元素的路徑中增加了額外的方法調用。

編者按(不涉及您的問題):

  • 不要使用new Integer(val)。取而代之的是使用Integer.valueOf(val),如果可用,它將重新使用盒裝整數,對於-128到127範圍內的值,這通常爲真。
  • 您可以使用IntStream而不是Stream<Integer>,它完全避免了裝箱開銷。它沒有完整的流操作,但它確實有iterate(),它具有一個在原始值int上運行的函數。
+3

或者你也可以使用'x - > x + 1',它更短,並且使用'Integer.valueOf'(剛纔用8u25和'javap -c -p'來驗證)。 – 2014-10-27 20:56:25