PR

 前回から、Project Lambdaについて改めて取り上げています。

 前回はラムダ式について解説を行いましたので、今回からStream APIについて取り上げていきます。

 基本的には、Stream APIを使いこなす方法をメインに紹介していく予定です。しかし、Stream APIはかなりボリュームのあるAPIなので、今回はStream APIの基本的な部分を紹介していきます。このため、過去の連載と重なる部分もありますので、ご了承ください。

Stream APIとは

 Stream APIは内部イテレータを実現させるAPIです。では、内部イテレータが何かというところから説明しましょう。

 Javaでイテレータを実現するにはjava.util.Iteratorインタフェースか、拡張for文を使用してきました。例えば、リストの要素を拡張for文で標準出力に出力するには次のように記述します。

 

リスト1●外部イテレータの例

List<String> texts = ……;
    
for (String text: texts) {
    System.out.println(text);
}

 

 拡張for文ではイテレーションの処理を波括弧内に記述します。この例は単純な例なのでイテレーションする処理のみ記述しています。しかし、拡張for文では、波括弧内にbreak文やcontinue文などイテレータを制御するための式も記述できます。

 このことは、イテレータの制御をコレクションの外側で行っていることを示します。このことから、拡張for文やIteratorインタフェースを使用したイテレータは外部イテレータと呼びます。

 外部イテレータは、その特徴から、波括弧内にはイテレーションの処理とイテレータの制御が混在してしまいます。

 これに対し、内部イテレータはイテレータの制御をコレクションの内側で行います。イテレーションしたい処理は関数やクロージャで記述して、コレクションに指定します。

 例えば、Stream APIでは拡張for文的な処理を行うにはforEachメソッドを使用します。詳しくは後述しますが、リスト1をStream APIを使用した内部イテレータで書き直したのがリスト2です。

  

リスト2●内部イテレータの例

List<String> texts = ……;
    
texts.stream()
     .forEach(text -> System.out.println(text));

  

 forEachメソッドの引数に、ラムダ式でイテレーションの処理を記述します。イテレーションの制御を行うのはストリームで、リストの各要素はラムダ式の引数textに代入されます。

 外部イテレータに比べると、内部イテレータはどのような処理をイテレーションするのかが明確になります。また、イテレーションの外側と内側では変数のスコープが変わるため、イテレーションの処理を独立にしやすいという特徴もあります。

 その一方で、イテレータを制御できないため、外部イテレータに比べると記述性が劣ってしまいます。このため、外部イテレータでは記述できていた処理を、内部イテレータでは記述できないということもあります。