我有一段Stack<Object>
以下代码:
while(!stack.isEmpty()){
Object object = stack.pop();
// do some operation on object
}
如何使用 Java 8 Stream 实现此迭代,使其循环直到堆栈为空,并且在每次迭代中,应通过从顶部弹出一个元素来减少堆栈?
我有一段Stack<Object>
以下代码:
while(!stack.isEmpty()){
Object object = stack.pop();
// do some operation on object
}
如何使用 Java 8 Stream 实现此迭代,使其循环直到堆栈为空,并且在每次迭代中,应通过从顶部弹出一个元素来减少堆栈?
在 Java 9 中,会有一个 3-arg 版本的 Stream.iterate(就像一个for
循环——初始值,用于确定输入结束的 lambda,用于确定下一个输入的 lambda)可以做到这一点,尽管它会是一个有点紧张:
if (!stack.isEmpty()) {
Stream.iterate(stack.pop(),
e -> !stack.isEmpty(),
e -> stack.pop())
...
}
如果您不想等待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 使用的元素,可能会使源处于不可预测的状态。短路操作可能不会消耗所有元素,并且与并行流结合使用时,它们仍然可能消耗比终端操作所需的更多元素。
执行终端流操作后,不能保证阅读器将处于读取下一个字符或行的特定位置。
Stack
在以这种方式消费元素后,您不应该对内容做出任何假设。
不可能使用堆栈的流,因为首先它将是先进先出的顺序,其次因为它基于迭代器会抛出一个ConcurrentModificationException
. 与简单的 for 循环相比,仍然可能,但当然不推荐:
IntStream.range(0, s.size()).forEach(i -> stack.pop());