Skip to content

Instantly share code, notes, and snippets.

@asufana
Last active January 23, 2017 22:44
Show Gist options
  • Save asufana/8310422 to your computer and use it in GitHub Desktop.
Save asufana/8310422 to your computer and use it in GitHub Desktop.
Java8 ラムダ式入門

Java8 ラムダ式入門

  • 社内勉強会資料

関数型プログラミング

参考:マルチコア時代のプログラマは関数脳になろう ⇒ http://goo.gl/O7GNrL

  • CPUマルチコア化が進む時代には並列処理が可能プログラムを書く能力が必要になる
  • 関数型プログラミングのメリット
  • 並列処理が容易(言語が行ってくれる)
  • 簡潔な記述、テスタビリティの向上
  • というか簡潔であればテスト不要とも言える(1+1のテストが必要かという話)

いまのJavaで出来る関数型アプローチ

  • 要は「イミュータブルなオブジェクト」に対する「閉じた操作(引数と戻り値の型が同じ)」を実現すれば関数的処理を実装できる ⇒ DDD参照 http://goo.gl/IqL4FF

  • VO操作:VOが自身と同じVOを引数に取るパターン

    Price price = price1.plus(price2).minus(price3);
    
  • リスト操作:AbstractCollection参照 http://goo.gl/3zkaXJ

    ContractDetailCollection details =
        new Contract.contractDetailCollection(details)
        .filterByNormal()
        .filterByWithoutProductOrder();
    
  • ContractDetailCollection自体は関数的な処理を実現しているが、残念ながら内部のリスト操作自体は関数的ではない(イテレータ)

    public ContractDetailCollection filterByNormal() {
        final List<ContractDetail> newList = new ArrayList<ContractDetail>();
        for (final ContractDetail contractDetail : list()) {
            if (contractDetail.isSkDummy()) { continue; } //ダミーは除外
            newList.add(contractDetail); //保守契約で普通のものだけ抽出
        }
        return new ContractDetailCollection(newList); //イミュータブル
    }
    

ではリスト操作を関数的に行うには?

  • Java7までのリスト操作はイテレータ(順に処理)であり関数(並列に処理)ではない
  • リスト操作を関数的に行うには「リスト自身が抽出条件を引数に取れる」必要がある
  • employeeList.find(条件:社員番号が1番)など
  • Java8からリストが拡張される、条件については次項

そもそもJava言語での条件記述には制約がある

  • Javaは引数としての最小粒度はクラス。つまり第一級オブジェクト(ファーストクラスオブジェクト)がクラスである。つまり引数として条件を渡す場合、必ずクラスにしないといけない。参照 ⇒ http://goo.gl/7MwrOf

  • JavaScriptは引数にfunctionを取ることができる、C#も引数にメソッドを取ることができる。これらの言語はファーストクラスオブジェクトが関数と言える。

  • 例えばJavaでカスタムソート(ソート"条件"がカスタム)を実現するためには、Comparatorインターフェースを実装した条件クラスを必要とする。2つのオブジェクトの比較だけのためにクラスが1つ必要。めんどくせーな。

  • 匿名クラスを使えば、インラインで記述することが出来、クラスファイル自体を作らなくても済む。

    Collections.sort(list, new Comparator<Employee>() {
        public int compare(Employee e1, Employee e2) {
            return e1.empId().compareTo(e2.empId());
        }
    });
    

条件記述をラムダ式で

  • Java8でもファーストクラスオブジェクトがクラスであることは変わらない。

  • ただし匿名クラスをより簡便に記述する方法としてラムダ式が提供される。

    list.sort((e1, e2) -> e1.empId() - e2.empId());
    
  • 言ってしまえば、ラムダ式とは匿名クラスの糖衣構文(シンタックスシュガー)に過ぎない

でも糖衣構文より重要なこと

  • ラムダ式で記述すると自動的に並列処理化される!

  • Java7まで

  • リスト処理がイテレータ ⇒ 順番に処理される ⇒ つまりシーケンシャル処理 ⇒ 並列化終わった\(^o^)/ ⇒ せっかくのマルチコア台無し

  • 並列化は「開発者」が頑張らないといけない

  • Java8以後

  • リスト処理が関数化 ⇒ ばらばらに処理できる ⇒ つまりパラレル処理 ⇒ 並列化意識しない\(^o^)/ ⇒ マルチコア使いまくり

  • 並列化は「ライブラリ」が頑張りますよ

    Integer sumOfWeights = blocks.stream()
        .filter(b -> b.getColor() == RED)
        .mapToInt(b -> b.getWeight())
        .sum();
    
  • 注)Java8でもイテレータで書いたら同じよ

じゃあJava8までどうするよ

  • Java8のリリースは2014/3予定
  • そもそもEclipseが対応しないと意味ない
  • ので現時点ではLambdaJなど、ラムダ式フレーバーなライブラリを使う
  • 並列化は期待できない。イテレータより重い。でも簡潔に記述できる。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment