4

我有一段Stack<Object>以下代码:

while(!stack.isEmpty()){
    Object object = stack.pop();
    // do some operation on object
}

如何使用 Java 8 Stream 实现此迭代,使其循环直到堆栈为空,并且在每次迭代中,应通过从顶部弹出一个元素来减少堆栈?

4

3 回答 3

7

在 Java 9 中,会有一个 3-arg 版本的 Stream.iterate(就像一个for循环——初始值,用于确定输入结束的 lambda,用于确定下一个输入的 lambda)可以做到这一点,尽管它会是一个有点紧张:

if (!stack.isEmpty()) {
    Stream.iterate(stack.pop(), 
                   e -> !stack.isEmpty(), 
                   e -> stack.pop())
          ...
}
于 2016-07-03T14:15:09.727 回答
1

如果您不想等待Java 9 解决方案,这里有一个在 Java 8 下工作的流工厂。

public static <T> Stream<T> pop(Stack<T> stack) {
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(
        stack.size(), Spliterator.ORDERED|Spliterator.SIZED) {
            public boolean tryAdvance(Consumer<? super T> action) {
                if(stack.isEmpty()) return false;
                action.accept(stack.pop());
                return true;
            }
    }, false);
}

请注意,这报告了堆栈的初始大小,认为这是理所当然的,这意味着您不能更改中间的堆栈(无论如何修改中间的流源是一个坏主意)。另一方面,这将使某些 Stream 操作比迭代变体更有效。

现在,适用于这两种变体的一般警告。由于正在进行的 Stream 操作而修改的流源,例如弹出 Stream 使用的元素,可能会使源处于不可预测的状态。短路操作可能不会消耗所有元素,并且与并行流结合使用时,它们仍然可能消耗比终端操作所需的更多元素。

如此类似于BufferedReader.lines()

执行终端流操作后,不能保证阅读器将处于读取下一个字符或行的特定位置。

Stack在以这种方式消费元素后,您不应该对内容做出任何假设。

于 2016-07-04T13:50:50.407 回答
-1

不可能使用堆栈的流,因为首先它将是先进先出的顺序,其次因为它基于迭代器会抛出一个ConcurrentModificationException. 与简单的 for 循环相比,仍然可能,但当然不推荐:

IntStream.range(0, s.size()).forEach(i -> stack.pop());
于 2016-07-02T12:24:57.257 回答