Java8 ラムダとStreamAPIを理解する

More than 3 years have passed since last update.


目的

Java8で導入されたラムダとStreamAPIについていろいろ調べたのでメモする(すべてJavaの話です)


ラムダ式


  • ラムダ式は、関数型インターフェースを使ってラムダ計算を実装する構文


    • 関数型インターフェースは、一つのAbstractメソッドしか持たないインターフェースのこと


      • Comparator/Runnable/Function/Predicateなど



    • ラムダ計算は、識別子/無名関数/関数適用の3つの要素だけで式が表現される計算モデル


      • JavaではJVMで直接関数を扱うのではなく、クラスのインスタンスを使って表現している





  • 型推論で変数の型定義が省略できる。


    • 省略しなくてもいい。


      • 省略されすぎると、見慣れないため意味がわからない。


        • そのうち慣れる。







  • クロージャーではない。


    • ローカル変数は実質的にfinalな変数にしかアクセスできない。(変更できない)

    • 独自のスコープは持たない。(ローカル変数と同じ変数名は利用できない)



  • 無名内部クラス(匿名クラス)はラムダ式に置き換え可能(ほぼ問題なく(thisの扱いが違う))


    • 似ているが実行時の呼び出しが異なる。


      • ラムダは実行時にクラスが生成される


        • 匿名クラスのようにコンパイル時にクラスを生成するとクラスロードが遅くなるため


          • 2回目以降の呼び出しは速い





      • ラムダのインスタンスは、VMが最適な生成方法を選択するらしい。


        • JVMの実装によっては今後も改善される可能性あり。








StreamAPI


  • ラムダ式と組み合わせて使うパイプライン型のデータ処理を実現するAPI


    • メソッドチェーン形式で記述



  • ソース、中間操作、終端操作の3つの構成要素からなる。


    • ソース:list.stream()(1つだけ)

    • 中間操作:.map(User::name)(複数指定可能)

    • 終端操作:.collect(Collectors.toList());(1つだけ)



  • 並列化が容易


    • StreamAPIを利用しないで並列処理を書く場合にくらべコード量が減る

    • 遅延評価で処理速度アップ




メリット


  • コード量が減る

  • より直感的にコードを理解できる

  • 並列処理を気軽に実装できる


    • 現在の基盤の資源を最大限に活かすためには並列処理が必要




デメリット


  • forの構文とラムダ式が混ざるとコードの可読性は下がる。

  • すべてラムダで表現しようとするとコードの可読性は下がる(と思っている)

  • 並列化して速度が必ずしも上がるわけではない。(デメリットではないが)

  • 標準の関数型インターフェースを利用する場合は、例外を投げれないのでラムダの中で処理しなければならない。


参考文献

実はこれが大事


まずはざっと理解する

社内Java8勉強会 ラムダ式とストリームAPI

- この資料のStreamAPIまでの章を理解しておけば、うんちくが語れます。

ひしだま's 技術メモページ Javaラムダ式

- レイアウトがWeb1.0で読みにくいが実はわかりやすい

きしだのはてな Java8 Lambdaの文法拡張まとめ

- なんとなく頭に入りやすい。


より深く知る(概念系)

Java Day Tokyo Lambda: A Peek Under The Hood

- ラムダと内部クラスの違いをInvokedynamicからのバイトコード呼び出しとそのパフォーマンスを混じえて説明

IBM DeveloperWorks Java 8 言語での変更内容

- 文章が多い。さらなるうんちくをえるためには参考になった。

Java Day Tokyo Javaの関数型言語への挑戦/ベターオブジェクト指向言語からの脱皮

- Javaのラムダと関数型言語との違いをわかりやすく説明

関数型言語のウソとホント

- Javaには関係なく関数型プログラミング言語に関する記事。

- これを読むとJavaのラムダが中途半端で申し訳なくも感じる。


実用編

とにかく書き方を知りたい

ラムダ式と関数型インタフェース

Java8 StreamAPI

今更人に聞けないJava5からの新機能(Java SE 8)

(o1, o2) -> o1 - o2 なんて呪文はもうやめて! - Java8でのComparatorの使い方

- ソートについてはこれはわかりやすい


その他、ラムダですべてハッピーになれるわけはない

Java 8のStream APIの性能まとめ

forループからStream API移行に関する適当な感想