前回までのあらすじ
Streamを求めてジャバ八村にやってきた俺たちは、Streamでよく使うと思われるラムダ式を調べ始めたが、その元となる関数型インターフェースの裏にはデフォルトメソッドとstaticメソッド、それにラムダ式にからんで実質的finalの新仕様が隠されていた。
そしてラムダ式と対になるメソッド参照やStreamと共に導入されたOptionalを経て、ついに俺たちはStreamに辿り着いたのだった。
という訳で、Streamを調べる前に関係していそうな新仕様を先に確認して、ようやくStreamを見ることが出来た。
Scalaのコレクションのメソッドに比べると少ないが、それでもそこそこメソッドは存在している。
結局ほとんどの面においてScalaの方が便利ではあるのだが、Java8が関数型言語への入門としてStreamを導入したのであれば、まずは基本的に使うものだけでいいという判断なのかな?
何にしても、mapメソッドが使えるのは嬉しい(笑)
しかしJavaにはプリミティブ型というものがあるので、実行効率(速度)を求めるなら、プリミティブ型のまま操作できる必要がある。
その為にオブジェクトを対象とするStreamの他にIntStreamやLongStream・DoubleStreamを用意している。
また、値を変換するmapメソッドも、プリミティブに変換する為のmapToInt()・mapToLong()・mapToDouble()といった別のメソッドが用意されている。(Scalaだったら、数値型かどうかに関係なくmapメソッドだけ使えばいいのだが)
この辺り、プリミティブ型を持つJava言語としては頑張って用意したなぁという感じではあるのだが、関数型言語に不慣れな初心者にとってはどれを使えばいいのか混乱を招きそうな上に、他の関数型言語に慣れたモヒカンにとっては面倒なだけ(あるいはマサカリを投げる標的を増やしただけ)だorz
また、ListやMapといった従来のコレクションに追加された関数型言語風メソッドは概ねforEachくらいで(せめてmapだけは欲しかった)、そういったメソッドを使いたければ一旦Streamに変換する必要がある。これはstream()やparallelStream()メソッドとして用意されているので、Javadocを見ただけですぐ分かるのだが。
しかしStreamから他のコレクション(ListやSet等)へ変換する方法は、ScalaだとtoListやtoSetといったメソッドが用意されているのだが、Java8ではcollectメソッドにCollectorオブジェクト(Collectors.toList()やtoSet())を渡すことで実現している。ユーティリティーみたいな別クラスになっているので、その気になれば新しいメソッドを追加するのは簡単だ。
よくこんな仕組みを考えたものだと感心するが、しかしStreamのcollectメソッドのJavadocを見て「Listに変換するにはこれを使えばいいんだ!」と思いつく人は(特に初心者には)いないと思う。
結局、Javaで関数型言語っぽい基本的な使い方をするにはStreamは充分使えるが、Java固有の面倒くささが新たに作られてしまっていて、関数型言語の初学者(関数型言語の勉強の入り口)としては地雷になりそうorz
ちなみに、ラムダ式はけっこうシンプルなので(今のところプレースホルダーも無いし)、覚えるのはそんなに難しくないし、見たときに「何をしているのか」も比較的簡単に分かると思う。
むしろ、誤解を招きそうなのはメソッド参照の方。特に「クラス名::メソッド名」という指定方法がstaticメソッドでもインスタンスメソッドでも可能なのは、後から見たときにちょっと混乱しそうな気がする。
(ラムダ式を書く場合、たいていは引数の型を省略するが、引数の個数や引数名から、何をするものなのかは想像が付く可能性がある。しかしメソッド参照だと、そういう情報はすっぱり落ちてしまう)
まぁ、たぶん慣れの問題、あるいはIDEの支援機能次第だけど。
メソッド参照を使うときれいに書けることもあるしね。→コードポイントの例(どのオーバーロードを使っているのか分かりにくいんだが…、しかしこれはこの例がちょっと特殊な方かもしれない?)
もし「将来的に時代についていけなくして会社を滅ぼす為に、新機能を禁止して“勉強する気のない人間でも分かる”コーディング規約を作れ」と言われたら、僕はラムダ式を禁止するより先にメソッド参照を禁止するね(爆)
※コメント投稿者のブログIDはブログ作成者のみに通知されます