ラムダ式の基本とその背景

## はじめに
本記事ではJavaのラムダ式および関数型インタフェースの基本とその背景について説明していきます。

## 対象者
・ラムダ式および関数型インタフェースを初めて学ぶ初心者
・基礎的な知識を習得済みで、再確認や実践例を通じて理解を深めたい方

## ラムダ式とは何か？
### ラムダ式の背景
Javaのラムダ式は、Java 8で導入された機能です。
それ以前のJavaではサポートされていなかった「関数型プログラミング」の概念を取り入れることで、コードの簡潔さと柔軟性を向上させ、複雑で多様なケースに応用が可能となりました。

例として、Java 8より前のバージョンでは、匿名クラスを使ってインタフェースを実装する場合、多くのコードを記述する必要がありました。
以下は、`Runnable`インタフェースを匿名クラスとして実装し、`run`メソッドをオーバーライドした例になります。
```java
Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, World!");
    }
};
```

以下は、同じ処理をラムダ式で書き直した例です。
ラムダ式の導入によって、コードの量を最小限に抑えることができ、匿名クラスを使った面倒な記述が必要なくなったため、簡潔に記述できるようになりました。
```java
Runnable task = () -> System.out.println("Hello, World!");
```

### ラムダ式の構文とルール
#### 基本構文
ラムダ式の基本構文は以下になります。
```java
(型1 引数名1, 型2 引数名2, ...) -> {
    処理;
}
```

引数の型は暗黙的に推論されるため、省略するのが一般的です。
また、実行結果を呼び出し元に返す場合は、コードブロック内において`return`文によって戻り値を指定します。

#### 省略記法
ラムダ式では、状況に応じて記述を簡略化できる場合があります。
以下のラムダ式を題材に、省略記法のルールについて説明していきます。
```java
Function<Integer, Integer> func = (Integer x) -> {
    return x * 2;
};
```

まず、代入時はラムダ式の引数宣言における型を省略可能です。
これはJavaコンパイラがラムダ式の代入先である変数の型（`Function<Integer, Integer>`）から推論できるためです。
```java
Function<Integer, Integer> func = (x) -> {
    return x * 2;
};
```

次に、ラムダ式の引数が1つの場合は丸カッコ`()`を省略可能です。
※引数を一つも取らない場合は丸カッコ`()`を省略できません。
```java
Function<Integer, Integer> func = x -> {
    return x * 2;
};
```

最後に、ラムダ式のブロック内の命令文が一行の場合は波カッコ`{}`を省略可能です。
この場合、対象の命令文が`return`の場合は、`return`キーワードも省略が必要です。
```java
Function<Integer, Integer> func = x -> x * 2;
```

### ラムダ式の動作原理
ラムダ式は、あくまで「関数型インタフェースの実装を簡潔に書く記法」です。
裏では匿名クラスのように関数型インタフェースを実装するオブジェクトが生成されています。

#### 関数型インタフェースとは
関数型インタフェースとは、抽象メソッドを一つだけ持つインタフェースのことを指します。
抽象メソッドが一つだけであれば、静的メソッドやデフォルトメソッドが含まれていても、関数型インタフェースとして扱うことができます。
以下は、`java.util.function`パッケージの`Function`インタフェースの実装です。（JavaDocコメントは省略）
```java:java.util.function.Function
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
```

`Function`インタフェースの詳細については公式ドキュメントをご確認ください。
[Function (Java Platform SE 8)](https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/Function.html)

#### FunctionalInterfaceアノテーション
`@FunctionalInterface`アノテーションは、インタフェースが関数型インタフェースであることを明示するためのアノテーションです。
Javaコンパイラが関数型インタフェースとして正しいかをチェックし、不正な実装（例：抽象メソッドが複数ある）を検出します。
以下のコードでは、正しい関数型インタフェースを作成しています。
```java
@FunctionalInterface
interface MyFunctionalInterface {
    void method();  // 抽象メソッド
}
```

但し、次のように複数の抽象メソッドを定義した場合、`@FunctionalInterface`アノテーションのチェックによりコンパイルエラーとなります。
```java
@FunctionalInterface
interface MyFunctionalInterface {
    void method1(); // 抽象メソッド
    void method2(); // 抽象メソッド（エラー）
}
```

#### ラムダ式と関数型インタフェースの関連
上述の通り、ラムダ式は「関数型インタフェースの実装を簡潔に書く記法」です。
ラムダ式と関数型インタフェースの関連について、例を用いて説明します。

**【関数型インタフェースの定義】**
```java
@FunctionalInterface
interface Greeting {
    void sayHello(String name);
}
```

**【ラムダ式を使った実装】**
```java
public class Main {
    public static void main(String[] args) {
        // ラムダ式を使用して、Greetingインタフェースを実装
        Greeting greeting = name -> System.out.println("Hello, " + name + "!");
        
        // 実行
        greeting.sayHello("World");
    }
}
```

**【出力結果】**
```
Hello, World!
```

この例では、`Greeting`インタフェースの `sayHello`メソッドをラムダ式で実装しています。  
ラムダ式は実行時に`Greeting`インタフェースを実装するオブジェクトとして振る舞い、`sayHello(String name)`メソッドに対応します。
ラムダ式は特定の関数型インタフェースの抽象メソッドと結び付けられることで、シンプルかつ効率的なコード記述を可能にしています。