8では、ラムダ式の導入に伴い、並列処理の実装を容易にする新APIとして「ストリームAPI」が追加された。その効果的な使い方を、前回の記事に続いて米国オラクルのスチュアート・マークス氏が解説する。SEの仕様策定をリードするスチュアート・マークス氏によるラムダ式の基礎解説をお届けした。8でラムダ式のサポートに伴って導入された新機能「ストリームAPI」に関するマークス氏の解説をお届けする。2014」におけるスチュアート・マークス氏のセッション「Lambda式とストリームAPI、並列処理の詳細」を基に構成しています。API)」の追加です。ストリームAPIはラムダ式をベースにして設計されたもので、これを使うことによってパイプラインや並列処理を容易かつスマートに実装することができます。今回は、このストリームAPIの基本的な使い方や並列処理の実装方法などを説明します。ストリームAPIには、曖昧な理解のまま使うと誤った結果を返したり、想定したパフォーマンスが得られなかったりするような落とし穴があります。そのような陥りやすい問題点についても、コードを例示しながら解決方法を紹介します。自動で電話をかける「Robocallシステム」を題材にして考える今回の記事でも、前回の記事で使った「Robocallシステム」を題材にして説明していきましょう。Robocallシステムは、連絡先のリストの中から、特定の条件にマッチする人に自動的に電話をかけるシステムです。連絡先などの個人情報はクラスPersonのオブジェクトとして管理し、Personオブジェクトの情報を基に条件を満たすか否かを判断して電話をかける処理をメソッドrobocallMatchingPersonsとして実装します。このメソッドの引数としては、条件をテストするメソッドtestを持った関数型インタフェースPersonPredicateのオブジェクトを渡します。8ではラムダ式を使って次のように書くことができます。メソッドrobocallSelectiveServiceCandidatesは「18歳から25歳までの男性」という条件を、メソッドrobocallEligibleDriversは「16歳以上(性別問わず)」という条件を指定してメソッドrobocallMatchingPersonsを呼び出します。16);}Robocallにメッセージ送信機能を追加するそれでは、このシステムに「携帯電話の番号に対しては、電話をかける代わりにテキスト・メッセージを送信する」という機能を追加してみましょう。リスト2のメソッドrobocallMatchingPersonsと同じ実装からスタートし、それをリファクタリングしていきます。最初の実装例は次のようになります。}}メソッドrobocallMatchingPersonsとtxtmsgMatchingPersonsの違いは、条件を満たす人に対して電話をかけるのか、それともメッセージを送るのかという点だけです。そこで、これらのメソッドを共通化し、呼び出し元で条件を満たした場合のアクションを決められるライブラリとして実装してみます。それには、初めに電話番号を受け取って最終的なアクションを実行する処理を関数型インタフェースとして次のように定義します。num);}Robocallシステム側のライブラリは、このインタフェースを使うと次のように書くことができます。引数としてPersonPredicateオブジェクトに加えてPhoneNumberConsumerオブジェクトを受け取り、robocallやtxtmsgなどのアクションをPhoneNumberConsumerに委譲するという仕組みです。}}次に、Personオブジェクトが固定電話と携帯電話の2つの番号を持つ場合を想定して、メソッドgetPhoneNumberは固定電話の番号を返し、携帯電話の番号はメソッドgetMobilePhoneNumberで取得するような仕様を考えてみます。この場合、電話をかけるときとメッセージを送るときでは電話番号の取得に使うメソッドが異なるため、メソッドprocessMatchingPersonsの実装を変更する必要が生じます。そこで、電話番号の取得方法も次のように関数型インタフェース化し、呼び出し側で指定できるようにします。p);}このインタフェースを使ってメソッドprocessMatchingPersonsを実装すると、次のようになります。}}呼び出し側は、3つの引数部分をそれぞれラムダ式化して、次のように書くことができます。関数型インタフェースを使うことにより、メソッドprocessMatchingPersonsの内部で行う条件判定や具体的なアクションを呼び出し側で実装できるようになっているのがポイントです。txtmsg(num));}さて、ここまでに次の3つの関数型インタフェースを定義しました。p);}ジェネリクスを使えば、これらをより一般化されたインタフェースとして定義することができます。具体的には、次のようにPersonやPhoneNumberの部分を型パラメータ化するのです。8で新たに追加されたアノテーションで、このインタフェースが関数型インタフェースであることを示しています。このジェネリクス化された関数型インタフェースに合わせてメソッドprocessMatchingPersonsを書き直すと、次のようになります。●map:フィルタリング。●filter:マッピング。お試しいただけるトライアル・サービスをご提供しております。permission.×このサイトでは、利用状況の把握や広告配信などのために、Cookieなどを使用してアクセスデータを取得・利用しています。これ以降ページを遷移した場合、Cookieなどの設定や使用に同意したことになります。Cookieなどの設定や使用の詳細、オプトアウトについては詳細をご覧ください。