Stack<Object>
次のコードがあります。
while(!stack.isEmpty()){
Object object = stack.pop();
// do some operation on object
}
スタックが空になるまでループし、すべての反復で上から 1 つの要素をポップしてスタックを減らす必要があるように、Java 8 Stream を使用してこの反復を実装するにはどうすればよいですか?
Stack<Object>
次のコードがあります。
while(!stack.isEmpty()){
Object object = stack.pop();
// do some operation on object
}
スタックが空になるまでループし、すべての反復で上から 1 つの要素をポップしてスタックを減らす必要があるように、Java 8 Stream を使用してこの反復を実装するにはどうすればよいですか?
Java 9 では、これを行うことができる Stream.iterate の 3 引数バージョン (for
ループ -- 初期値、入力の終わりを決定するためのラムダ、次の入力を決定するためのラムダのような) があります。少し緊張:
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 操作が iterate バリアントよりも効率的になります。
さて、両方の亜種に適用される一般的な警告です。Stream が消費する要素をポップするなど、進行中の Stream 操作のために変更されたストリーム ソースは、ソースを予測できない状態のままにすることができます。短絡操作はすべての要素を消費しない可能性があり、並列ストリームと組み合わせると、端末操作に必要な以上の要素を消費する可能性があります。
とても似ているBufferedReader.lines()
端末ストリーム操作の実行後、リーダーが次の文字または行を読み取る特定の位置にいるという保証はありません。
Stack
このように要素を消費した後は、コンテンツについて何の仮定もすべきではありません。
最初は先入れ先出しの順序になるため、スタックのストリームを使用することはできません。次に、イテレータに基づいているため、ConcurrentModificationException
. それでも可能ですが、単純な for ループと比較するともちろん推奨されません。
IntStream.range(0, s.size()).forEach(i -> stack.pop());