Stream APIが提供しているのが、関数型言語の機能を取り入れた内部イテレータであるストリームとなる。
ストリームはリストなどのコレクションとは異なり、自分自身は要素を保持しない。
その代わりに、コレクションなどの要素を参照してイテレートしていく。
ストリームは、Iteratorインタフェースと同じように、一度イテレートしてしまったストリームを再利用することはできない。
ストリームではイテレートしながら行う処理が多数定義されている。これらの処理を組み合わせて、最終的な結果を得る。このように複数の処理を組み合わせて処理することを「ストリームパイプライン」と呼びます。
ストリームが定義している処理にはパイプラインの中間に使用できる中間操作と、パイプラインの最後にだけ使用できる終端操作があります。
中間操作はfilterメソッドやmapメソッドのように、戻り値がストリームになっているメソッドが当てはまる。一方、終端操作は戻り値がストリーム以外の 型になっているメソッドが当てはまる。
ストリームパイプラインの例
Stream<String> stream = ,,,;
stream.filter(text -> text.length() > 10) // 中間操作
.forEach(text -> System.out.println(text)); // 終端操作
この場合、filterメソッドが中間操作、forEachメソッドが終端操作となる。
中間操作と終端操作に分けている理由は実行時の効率にあります。
単純にfilterメソッド、forEachメソッドの順に処理を行うと、filterメソッドで1回、forEachメソッドで1回の合計2回のイテレーションが行われてしまう 。
これでは、パイプラインが長くなればなるほど、イテレーションが行われてしまい、パフォーマンスが落ちてしまう。
そこで、Stream APIでは、中間操作はその場では処理を行わずに、終端操作でまとめて処理を行うように設計されている。
このようにすることで、パイプラインの長さに関係なく、常に1度のイテレーションで処理を行うことができる。