こまぶろ

技術のこととか仕事のこととか。

StreamとOptionalに共通して存在するメソッド:filter(Predicate<? super T> predicate)

Java 8 で導入されたStreamとOptional。業歴は浅いのに古いJavaで学んでしまったので、いざ使える状況になったにもかかわらずいまいち使い方がよくわかっておらず、書籍やWeb上の資料で知識を補っている最中だ。

調べているうちに、Stream(インタフェース)とOptional(クラス)との間には、(名称が)共通のメソッドがいくつか存在することに気が付いた。APIドキュメントを見比べると、以下のものがそれに当たる。

  • filter()
  • flatMap()
  • map()
  • of()
  • ofNullable()

StreamとOptionalについての勉強の手始めに、これらについて調べてみることにした。これらのうち、filter()of()ofNullable()は引数の数と型も一致(=シグネチャが一致)している。今回は、このうちのfilter()について、StreamのそれとOptionalのそれとの比較を試みる。

述語を満たす要素を残す

filter()の引数は、いずれもPredicate<? super T> predicateだ。Predicateは関数型インタフェースで、ひとつの入力に対してbooleanの判定結果を返すtest()メソッドを持つ。具体的な事例では、下記のような形で用いられる。

number.filter( n -> n % 2 == 0) // number は Optional or Stream

上のコードでは、numberの要素に対して、それが偶数であるかを判定している。判定結果がfalseとなる場合、Optionalでは判定結果がfalseであれば空のOptilnal(Optional.empty()の返り値)が返却されるのに対し、Streamでは当該要素を除いた要素で新たなStreamが返却される。

いずれにおいても、判定結果がfalseになる要素を除外する(trueになる要素のみを残す)という意味合いは共通していることがわかる。OptionalもStreamも中に要素を持つ「入れ物」としてイメージできるが、その要素をなんらかの基準によって選別するという機能をfilter()は持っている。

OptionalとStreamの違い

ただし、両者の間には当然ながら違いもある。「入れ物」としてのOptionalとStreamの違いは、Optionalは要素を1つしか持たないのに対し、Streamは0から多数の要素を持つことができる、という「要素の数」の違いとして整理しても間違いではないと思う。しかし、filter()の挙動からすると、両者の間には要素の数以上の違いがあることも見えてくる。

Optionalは、1つの要素を持つというよりは、1つを収めるスペースを持っていると表現すべきだろう。判定結果がfalseの場合のfilter()の返り値は、空のOptional、すなわち「1つ分のスペースが空席の」Optionalである。そこには、空席にはなっているものの、要素1つ分のスペースが確かに残っている。これに対し、Streamのfilter()は要素の数が単純に減った新しいStreamが返される。filter()を受ける前に存在していた要素の痕跡は残らない。

次回予告

今回は、filter()について調べた。言及したOptionalとStreamの違いは、その他の共通のメソッドにも反映されているはずなので、これからまた調査したい。