Optionalの基本まとめ

# Optionalとは？
Optionalは値がnullの可能性があることを明示的に表現するためのクラスです。
また、値がnullである場合のハンドリングを簡単にするメソッドが用意されています。
## Optionalクラスの代表的なメソッド
### インスタンスの生成
| シグニチャ | 説明 |
|:--|:--|
| **static<br>\<T> Optional<T> empty()** | 値が存在しない空のOptionalインスタンスを返します。  |
| **static<br>\<T> Optional<T> of(T value)** | 引数で渡された値を持つOptionalインスタンスを返します。 nullを渡すと**NullPointerException**で実行時エラーになります。 |
| **static<br>\<T> Optional<T> ofNullable(T value)** |  引数がnullならば空の、nullでないなら引数を値に持つOptionalインスタンスを返します。 |
```Java:OptinalSample.java
import java.util.Map;
import java.util.Optional;
import java.util.Random;

public class OptionalSample {
    // IDをキー、名前を値に持つ名簿Map
    public static final Map<Integer, String> membershipList = Map.of(1, "James", 2, "Michael");

    public static void main(String... args) {

    }

    public static Optional<String> optionalLookUpNameById(int id) {
        if(membershipList.containsKey(id)) {
            return Optional.of(membershipList.get(id));// idに対応するnameを値に持ったOptionalインスタンスを返します。
        }

        return Optional.empty(); // 空のインスタンスを返します。
    }

    public static Optional<String> nullableOptionalLookUpNameById(int id) {
        return Optional.ofNullable(membershipList.get(id)); // 存在しないidのときは空のインスタンスを返します。
    }

}
```
### 値の取得
| シグニチャ | 説明 |
|:--|:--|
| **T get()** | Otionalが持っている値を返します。値がない場合は**NoSuchElemenetException**をスローします。  |
| **T orElse(T other)** | Optionalが持っている値を返します。値がない場合は引数otherを返します。  |
| **T orElseGet(Supplier<? extends T> supplierr)** | Optionalが持っている値を返します。値がない場合は引数に渡したSupplier型のラムダ式が値を返します。 |

```Java:OptinalSample.java
Optional<String> optionalName = optionalLookUpNameById(1);
String output = optionalName.get(); // Optionalの値はget()で取り出します。
System.out.println(output); // James

Optional<String> optionalEmpty = optionalLookUpNameById(0); // キーに0が存在しないので、空のOptionalが返ります。
// name = optionalEmpty.get(); 空のOptionalから値を取り出そうとすると、NoSuchElementExceptionで実行時エラーとなります。

output = optionalEmpty.orElse("No Such Element"); // 空のOptionalインスタンスが呼び出しているので、引数に渡された値が返されます。
System.out.println(output); // No Such Element

output = optionalEmpty.orElseGet(() -> "is Empty"); // 空のOptionalインスタンスが呼び出しているので、引数渡したラムダ式が値を返します。
System.out.println(output); // is Empty
```

### 値の存在確認
| シグニチャ | 説明 |
|:--|:--|
| **boolean isPresent()** | 値が存在するときはtrue、存在しないときはfalseを返します。  |
| **boolean isEmpty()** | 同じインスタンスで呼び出し時、isPresent()の否定論理値を返します。  |
```Java:OptionalSample.java
System.out.println(optionalName.isPresent());// true
System.out.println(optionalName.isEmpty()); // false
```

### その他
| シグニチャ | 説明 |
|:--|:--|
| **void ifPresent​(Consumer\<? super T> action)** | 値が存在するときのみ、値を引数に取るラムダ式actionを実行します。  |
| **\<X extends Throwable> T orElseThrow​(Supplier\<? extends X> exceptionSupplier)<br>throws X extends Throwable** | 値が存在するときは値を返し、値が存在しないときは引数に渡したラムダ式が生成する例外をスローします。 |
```Java:OptionalSample.java
optionalName.ifPresent(s -> System.out.println("名前の文字数は" + s.length() + "文字です。")); // 名前の文字数は5文字です。

Optional<String> nullableOptionalEmpty = nullableOptionalLookUpNameById(0);
try {
    nullableOptionalEmpty.orElseThrow(() -> new Exception("値が存在しません。"));
} catch (Exception e) { // 検査例外をThrowしたときはcatchしなければコンパイルエラーになります。
    System.out.println(e.getMessage()); // 値が存在しません。
}
```

## Optionalを使わない場合
```Java:OptionalSample.java
public static String lookUpNameById(int id) {
    return membershipList.get(id);
}

public static void main(String... args) {
    // Optionalを使わない場合
    String name = lookUpNameById(1);
    System.out.println(name); // James

    String nameNull = lookUpNameById(0); // キーに0が存在しないので、nullが返ります。
    // System.out.println("名前の文字数は" + nameNull.length() + "文字です。"); コメントアウトすると、NullPointerExceptionで実行時エラーとなります。

    // 実行時エラーを避けるためにnullチェックが必要で、コードが冗長になります。
    Random random = new Random();
    int randomId = random.nextInt(3);
    String randomName = lookUpNameById(randomId);
    if(randomName == null) {
        System.out.println("指定されたidは存在しません。");
    }
    else {
        System.out.println(randomName);
    }
}
```

## 参考資料
- [Optional (Java SE 11 & JDK 11 )](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Optional.html)
- [Effective Java 第3版](https://www.amazon.co.jp/dp/B099922DML/)
- [オラクル認定資格教科書 Javaプログラマ Gold SE11（試験番号1Z0-816）](https://www.amazon.co.jp/%E3%82%AA%E3%83%A9%E3%82%AF%E3%83%AB%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8-Java%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E-Gold-SE11%EF%BC%88%E8%A9%A6%E9%A8%93%E7%95%AA%E5%8F%B71Z0-816%EF%BC%89-%E5%B1%B1%E6%9C%AC-ebook/dp/B08P55ZJNY/ref=sr_1_4?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=14K4TS3X016UO&keywords=Java+Gold&qid=1647866067&s=digital-text&sprefix=java+gold%2Cdigital-text%2C220&sr=1-4)

本記事で利用しているサンプルコードはGitHubからForkしてご利用いただけます。
[サンプルコード URL](https://github.com/lrururu/qiita-sample-code/tree/main/src/_89ca4150aedca8a02b64)