Javaのラムダ式について今更まとめる

普段はスクリプト系言語使いです。

珍しくJavaを触る機会があったので、
うっすらしか知らなかったJavaのラムダ式について、
Java11リリースのご時世ではありますが確認の意味でまとめます。

# 1.ラムダ式導入以前
なんかすごいゲームの開発チームに入ったとします。
ユーザーの名前に関する部分を担当することになりました。
将来的にキャラごとに主人公に対する敬称が変わるので、そのあたりのAPIの整備を任されました。

名前のフォーマットを担当するインターフェースを定義します。

```java:NameFormatter.java
interface NameFormatter {
  public abstract String format(String familyName, String firstName);
}
```
実装クラスとメイン実行部はこんな感じ。

```java:Chanformatter.java
class ChanFormatter implements NameFormatter {
  @Override
  public String format(String familyName, String firstName){
    return firstName + "ちゃん";
  }
}
```
```java:Main.java
class Main {
  public static void main(String[] args){
    String familyName = "伊達";
    String firstName = "政宗";

    NameFormatter nf = new ChanFormatter();
    String formatted = nf.format(familyName, firstName);

    System.out.println("こんにちは！" + formatted + "。");
    System.out.println("なんかすごいゲームを始めるよ！");
  }
}
```
実行結果はコチラ

```
こんにちは！政宗ちゃん。
なんかすごいゲームを始めるよ！
```
馴れ馴れしいですね。

逆に、仰々しいキャラのために別のフォーマッタも用意しましょう。

```java:DonoFormatter.java
class DonoFormatter implements NameFormatter {
  @Override
  public String format(String familyName, String firstName){
    return familyName + "殿";
  }
}
```

メイン実行部でnewするクラスを変更するだけで呼び方も簡単に変えられます。

```java:Main.java(diff)
     String familyName = "伊達";
     String firstName = "政宗";
 
-    NameFormatter nf = new ChanFormatter();
+    NameFormatter nf = new DonoFormatter();
     String formatted = nf.format(familyName, firstName);
 
     System.out.println("こんにちは！" + formatted + "。");
```
```
こんにちは！伊達殿。
なんかすごいゲームを始めるよ！
```

## 1.1.無名クラス

さて、なんかすごいゲームの開発チームをクビになったとします。
こんなに小さなクラス群の整備に人員コストをかけられないからです。
開発チームではフォーマッタを無名クラスを用いて実装することにしました。

このくらいの規模のクラスに対してひとつひとつファイルを作るのではなく、
その場で定義して使い捨てるための機能が無名クラスです。

無名クラスを使うと、以下の2つのファイルのみで済みます。

```java:Nameformatter.java
// 再掲
// 前述のものと同じ
interface NameFormatter {
  public abstract String format(String familyName, String firstName);
}
```

```java:Main.java
class Main {
  public static void main(String[] args){
    NameFormatter chan = new NameFormatter(){
      @Override
      public String format(String familyName, String firstName){
        return firstName + "ちゃん";
      }
    };

    NameFormatter dono = new NameFormatter(){
      @Override
      public String format(String familyName, String firstName){
        return familyName + "殿";
      }
    };

    String familyName = "伊達";
    String firstName = "政宗";

    String formatted = chan.format(familyName, firstName);
    System.out.println("こんにちは！" + formatted + "。");
    System.out.println("なんかすごいゲームを始めるよ！");
  }
}
```
変数に対してフォーマット方法が紐付いている形です。

# 2.ラムダ式
さて、本題のラムダ式です。

今回のような状況の場合、
`NameFormatter`クラスが実装すべきメソッドは`format`のみです。
したがって、オーバーライドの対象は`format`メソッドしかありえません。
`public String format(String familyName, String firstName)`といちいちコピペするのも冗長な気がします。コンパイラによろしくやって欲しい。

そんな要望を叶えられる記法がラムダ式です。以下のように書けます。

```java:Main.java
class Main {
  public static void main(String[] args){
    NameFormatter chan = (String familyName, String firstName) -> {
      return firstName + "ちゃん";
    };

    NameFormatter dono = (String familyName, String firstName) -> {
      return familyName + "殿";
    };

    String familyName = "伊達";
    String firstName = "政宗";

    String formatted = chan.format(familyName, firstName);
    System.out.println("こんにちは！" + formatted + "。");
    System.out.println("なんかすごいゲームを始めるよ！");
  }
}
```

スッキリ書けました。以上。

# 3.それだけ？
ラムダ式についてはそれだけです。
ラムダ式自体はただの無名クラスの省略記法で、そんなに大きなトピックではありません。

本丸はラムダ式ではなく以下2点です。

- 関数型インタフェース（パッケージ`java.util.function`）
- Java Stream API

今回、`NameFormatter`というオリジナルなインターフェースを用いましたが、
ラムダ式を使うことが想定されたインターフェースが多数提供されています。
そのひとつが`java.util.function.Function<T,R>`です。

また、Java Stream APIとして`map`や`filter`など関数型によくあるメソッドも多数追加されました。
それらのメソッドは、引数に`java.util.function`のインターフェースを渡して使います。

# 4.結論
ラムダ式はこわくない。

# 5.感想
Stream APIをスラスラ使いこなせるようにしたいなあ

# 6.参考
[Java8のラムダ式を理解する - Qiita](https://qiita.com/sano1202/items/64593e8e981e8d6439d3)