Java SE 11 Silver 学習 ラムダ式


## はじめに
- [Oracle Certified Java Programmer, Silver SE 11 認定資格](https://www.oracle.com/jp/education/certification/1z0-815-jpn-48261-ja.html)の受験にあたり、Java11について学習／検証した内容を資料としてまとめる。
- 本ドキュメントは、[出題範囲](https://www.oracle.com/jp/education/certification/1z0-815-jpn-48261-ja.html#skill)のうち、以下出題範囲に対応する調査を行った結果となる。
    - インタフェースによる抽象化/ラムダ式の理解


## 本ドキュメントで解説する内容
- 関数型インタフェース
- ラムダ式
- メソッド参照
- コンストラクタ参照
- Java標準ライブラリにおける関数型インタフェース
        - Runnable/Callable
        - Comparator#compare
        - Supplier#get
        - Consumer#accept
        - Predicate#test
        - Function#apply
        - Operator#apply


### 関数型インタフェース
- 抽象メソッドが1つのみ定義されているインターフェース。
- ラムダ式、メソッド参照、またはコンストラクタ参照を使って関数型インタフェースのインスタンスを作成できる。

**TIPS**
- 関数型インタフェースにはstaticメソッドやデフォルトメソッドが含まれていても構わない（関数型インターフェースとしては無視される）
- `FunctionalInterface`アノテーションをインタフェース定義に追加すると、インタフェースが関数型インタフェースの要件を満たすかどうかを静的にチェックできる。

関数型インタフェースの例
```java
package java.util.function;

import java.util.Objects;

@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;
    }
}
```

### ラムダ式
- 関数型インターフェースのメソッドを実装（オーバーライド）する記法。
- インターフェース変数にラムダ式を代入することで、関数型インタフェースのインスタンスを簡易に記述できる。
  ```
  引数部 -> 本体部
  ```

**TIPS**
- 以下の2つの式により生成されるインスタンスは同一となる。
```java:無名クラス
  Function<Integer, String> f = new Function<>() {
    @Override
    public String apply(Integer i) {
        return String.valueOf(i);
    }
  };
```
```java:ラムダ式
  Function<Integer, String> ｆ = i -> String.valueOf(i);
```

**引数部**
- 引数部で定義された変数は、本体部のみで利用可能となる。
- ローカル変数と同一名称の変数を引数名に定義することはできない。

|引数の数|記法|記載例|
|:--|:--|:--|
|なし| ()|`() ->`|
|1つ|(型 変数名)|`(String name) ->`|
|^|(変数名)|`(name) ->`|
|^|変数名 |`name ->`|
|2つ以上|(型1 変数名1, 型2 変数名2)|`(String name, int i) ->`|
|^|(変数名1, 変数名2)|`(name, i) ->`|

**本体部**
  - 本体部の処理において、以下の変数にアクセスできる。
    - クラスのフィールド(インスタンス/クラスフィールド)
    - ラムダ式の定義以前に宣言済のローカル変数のうち、finalまたは実質的finalのもの

|戻り値|処理数|記法|記載例|
|:--|:--|:--|:--|
|void|1|処理を定義|`-> System.out.println("A");`|
|^|1以上|各処理を{}で囲む|`-> { a.hoge(); b.fuga(); }`|
|あり|1|値を返却する処理のみ定義|`-> String.valueOf(10);`|
|^|1以上|各処理を{}で囲み、returnで返却 |`-> { a.hoge(); return a; }`|

### メソッド参照
- 関数型インターフェースの変数にメソッドそのものを代入すること。
- 記法
  - インスタンスメソッドの場合: `変数名::メソッド名`
  - staticメソッドの場合: `クラス名::メソッド名`
  - 自クラスのインスタンスメソッドの場合: `this::メソッド名`

**TIPS**
- 以下の2つの式で実行される内容は同一となる。
    ```java:ラムダ式
      List.of(1,2,3).forEach(n -> System.out.print(n)); //123
    ```
    ```java:メソッド参照
      List.of(1,2,3).forEach(System.out::print); //123
    ```

### コンストラクタ参照
- 関数型インターフェースの変数にコンストラクタを代入すること。
- 記法: `クラス名::new`

**TIPS**
- 以下の2つの式で実行される内容は同一となる。
    ```java:ラムダ式
    List<Long> now = Arrays.asList(1680143332000L);
    now.stream().map(l -> new Date(l)).forEach(System.out::println); //Thu Mar 30 11:28:52 JST 2023
    ```
    ```java:コンストラクタ参照
    List<Long> now = Arrays.asList(1680143332000L);
    now.stream().map(Date::new).forEach(System.out::println);; //Thu Mar 30 11:28:52 JST 2023
    ```

### 標準の関数型インタフェース
- Java標準ライブラリにおいて関数型インタフェースが提供されている。
- 代表的な関数型インタフェースを以下に示す。

|package|関数型インタフェース|概要|
|:--|:--|:--|
|java.lang|Runnable#run|引数なしで処理を行い、結果を返さない(検査例外なし)|
|java.util.concurrent|Callable#call|引数なしで処理を行い、結果を返さない(検査例外あり)|
|java.util|Comparator#compare|2つのオブジェクトの大小比較を行う|
|java.util.function|Supplier#get|引数なしで処理を行い、任意の結果を返す|
|java.util.function|Consumer#accept|引数ありで処理を行い、結果を返さない|
|java.util.function|Predicate#test|引数ありで処理を行い、真偽値で結果を返す(条件判定)|
|java.util.function|Function#apply|引数ありで処理を行い、任意の結果を返す|
|java.util.function|UnaryOperator#apply|引数ありで処理を行い、引数と同一の型を返す|

- 参考: [java.util.functionパッケージ](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/function/package-summary.html)

### Runnable/Callable
|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|[Runnable](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/Runnable.html)|void run()|0|メソッドはどのようなアクションを実行してもかまわない|
|[Callable](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/concurrent/Callable.html)`<V>`|V	call()|0|結果を計算するか、計算できない場合は例外をスローする|


#### Comparator#compare
|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|[Comparator](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Comparator.html)`<T>`|int compare​(T o1, T o2)|2| o1がo2よりも小さい場合は負の整数、等しい場合はゼロ、大きい場合は正の整数を返す|


#### Supplier#get
- 引数なしで処理を行い、結果を返す。

|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|Supplier`<T>`|T get()|0|総称型(T)|
|BooleanSupplier|boolean getAsBoolean|0|boolean|
|IntSupplier|int getAsInt()|0|int|
|LongSupplier|long getAsLong()|0|long|
|DoubleSupplier|double getAsDouble()|0|double|

#### Consumer#accept
- 引数ありで処理を行い、結果を返さない。

|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|Consumer`<T>`|void accept(T t)|1|void|
|IntConsumer|void accept(int value)|1|void|
|LongConsumer|void accept(long value)|1|void|
|DoubleConsumer|void accept(double value)|1|void|
|BiConsumer`<T, U>`|void accept(T t, U u)|2|void|
|ObjIntConsumer`<T>`|void accept(T t, int value)|2|void|
|ObjLongConsumer`<T>`|void accept(T t, long value)|2|void|
|ObjDoubleConsumer`<T>`|void accept(T t, double value)|2|void|

#### Predicate#test
- 引数ありで処理を行い、真偽値で結果を返す(条件判定)。

|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|Predicate`<T>`|boolean test(T t)|1|boolean|
|Consumer`<T>`|boolean test(T t)|1|boolean|
|IntPredicate|boolean test(int value)|1|boolean|
|LongPredicate|boolean test(long value)|1|boolean|
|DoublePredicate|boolean test(double value)|1|boolean|
|BiPredicate`<T, U>`|boolean test(T t, U u)|2|boolean|

#### Function#apply
- 引数ありで処理を行い、結果を返す。

|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|Function`<T, R>`|R apply(T t)|1|総称型(R)|
|IntFunction`<R>`|R apply(int value)|1|総称型(R)|
|LongFunction`<R>`|R apply(long value)|1|総称型(R)|
|DoubleFunction`<R>`|R apply(double value)|1|総称型(R)|
|BiFunction`<T, U, R>`|R apply(T t, U u)|2|総称型(R)|
|ToIntFunction`<T>`|int applyAsInt(T value)|1|int|
|LongToIntFunction|int applyAsInt(long value)|1|int|
|DoubleToIntFunction|int applyAsInt(double value)|1|int|
|ToIntBiFunction`<T, U>`|int applyAsInt(T t, U u)|2|int|
|ToLongFunction`<T>`|long applyAsLong(T value)|1|long|
|IntToLongFunction|long applyAsLong(int value)|1|long|
|DoubleToLongFunction|long applyAsLong(double value)|1|long|
|ToLongBiFunction`<T, U>`|long applyAsLong(T t, U u)|2|long|
|ToDoubleFunction`<T>`|double applyAsDouble(T value)|1|double|
|IntToDoubleFunction|double applyAsDouble(int value)|1|double|
|LongToDoubleFunction|double applyAsDouble(long value)|1|double|
|ToDoubleBiFunction`<T, U>`|double applyAsDouble(T t, U u)|2|double|

#### Operator#apply
- 引数ありで処理を行い、引数と同一の型を返す。

|関数型インタフェース|メソッド|引数の数|戻り値|
|:--|:--|:--|:--|
|UnaryOperator`<T>`|T apply(T t)|1|総称型(T)|
|IntUnaryOperator|T applyAsInt(int operand)|1|int|
|LongUnaryOperator|T applyAsLong(long operand)|1|long|
|DoubleUnaryOperator|T applyAsDouble(double operand)|1|double|
|BinaryOperator`<T>`|T apply(T t, T u)|2|総称型(T)|