如何使用Java 8 Stream实现Stack Iteration

时间:2016-07-02 12:00:07

标签: java java-8 stack java-stream java-9

我有Stack<Object>及以下代码:

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

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

3 个答案:

答案 0 :(得分:7)

在Java 9中,将有一个3-arg版本的Stream.iterate(如for循环 - 初始值,lambda用于确定输入结束,lambda用于确定下一个输入)这样做,虽然会有点紧张:

if (!stack.isEmpty()) {
    Stream.iterate(stack.pop(), 
                   e -> !stack.isEmpty(), 
                   e -> stack.pop())
          ...
}

答案 1 :(得分:1)

如果您不想等待the Java 9 solution,这是一个在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内容做出任何假设。

答案 2 :(得分:-1)

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

IntStream.range(0, s.size()).forEach(i -> stack.pop());