クラス java.util.Optionalのおさらいメモ

# 概要

Java 1.8より導入されたjava.util.Optionalクラスのおさらいメモです。

**環境**

* Windows 10 Professional
* Oracle JDK 9.0.4
* Oracle JDK 10.0.1

**参考**

* [Oracle JDK 9ドキュメント] (https://docs.oracle.com/javase/jp/9/index.html)
* [Oracle JDK 10ドキュメント] (https://docs.oracle.com/javase/jp/10/index.html)


# [Optional\<T\> - Java 1.8] (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Optional.html)

## empty / of / ofNullable

いずれもstaticメソッドです。Optionalはpublicなコンストラクタを持たないのでOptionalオブジェクトを生成するにはこれらのメソッドを利用します。

**empty**

null値を持つOptionalオブジェクトを返します。

```java
Optional<String> empty = Optional.empty();
```

```java
empty.isPresent();
// false

empty.orElse("other");
// other

empty.get();
// java.util.NoSuchElementException: No value present
```

**of**

非null値を持つOptionalオブジェクトを返します。

```java
String str = "nonNull";
Optional<String> nonNullString = Optional.of(str);
```

```java
nonNullString.isPresent();
// true

nonNullString.get();
// result : nonNull
```

ofにnullなオブジェクトを渡すと例外がスローされます。

```java
String str = null;
Optional.of(str);
//  java.lang.NullPointerException
```

**ofNullable**

nullかもしれない値(nullable)を持つOptionalオブジェクトを返します。

```java
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);
```

```java
nullableString.isPresent();
// false

nullableString.orElse("other");
// other
```


## get / isPresent

**get**

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合はNoSuchElementExceptionがスローされます。

```java
String str = "apple";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.get();
// apple
```

```java
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.get();
// java.util.NoSuchElementException: No value present
```

**isPresent**

Optionalオブジェクトが保持する値が非nullの場合はtrue、nullの場合はfalseを返します。

```java
String str = "apple";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.isPresent();
// true
```

```java
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.isPresent();
// false
```

## orElse / orElseGet / orElseThrow

**orElse**

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合は指定した値を返します。(nullも可)

```java
String str = "nonNull";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElse("other");
// nonNull
```

```java
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElse("other");
// other

nullableString.orElse(null);
// null
```

**orElseGet**

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合は指定したSupplierの結果を返します。
Supplierがnullを返す場合はnullが返ります。

```java
String str = "nonNull";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElseGet(() -> "other");
// nonNull
```

```java
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElseGet(() -> "other");
// other

nullableString.orElseGet(() -> null);
// null
```

**orElseThrow**

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合は指定した例外がスローされます。

```java
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElseThrow(RuntimeException::new);
// java.lang.RuntimeException
```

## ifPresent

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するConsumerの処理ブロックを実行します。
Optionalオブジェクトが保持する値がnullの場合は例外はスローされず、またなにも実行されません。

```java
Optional<Employee> employee = Optional.ofNullable(new Employee(1L, "john"));
employee.ifPresent((e) -> {
    e.setName(e.getName().toUpperCase());
    System.out.println(e);
    // Employee{id=1, name='JOHN'}
});
```

## filter / map / flatMap

**filter**

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するPredicateの処理ブロックを実行します。

```java
Optional<String> nullableString = Optional.ofNullable("banana");

Optional<String> filtering = nullableString.filter(str -> str.length() > 5);
filtering.isPresent();
// true

filtering.orElse("other");
// banana
```

Optionalオブジェクトが保持する値がnullの場合、またはPredicateの処理ブロックがfalseを返す場合は空のOptionalが返ります。

```java
Optional<String> nullableString = Optional.ofNullable("apple");
// Optional<String> nullableString = Optional.ofNullable(null);

Optional<String> filtering = nullableString.filter(str -> str.length() > 5);
filtering.isPresent();
// false

filtering.orElse("other");
// other
```

**map**

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するFunctionの処理ブロックを実行します。

```java
Optional<String> nullableString = Optional.ofNullable("apple");
Optional<Integer> mapping = nullableString.map(str -> str.length());

mapping.isPresent();
// true

mapping.orElse(0);
// 5
```

Optionalオブジェクトが保持する値がnullの場合、またはFunctionの処理ブロックがnullを返す場合は空のOptionalが返ります。

```java
Optional<String> nullableString = Optional.ofNullable(null);
Optional<Integer> mapping = nullableString.map(str -> str.length());

mapping.isPresent();
// false

mapping.orElse(0);
// 0
```

**flatMap**

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するFunctionの処理ブロックを実行します。
mapとの違いはFunctionがOptionalオブジェクトを返す点です。

mapに指定するFunctionはT型を取りU型を返します。

```
Function<? super T,? extends U> mapper
```

flatMapに指定するFunctionはT型を取りOptional<U>型を返します。

```
Function<? super T,Optional<U>> mapper
```

```java
Optional<Long> optId = Optional.of(1L);
Optional<String> optName = Optional.of("john");

Optional<Employee> result = optId.flatMap(id -> optName.flatMap(name -> Optional.of(new Employee(id, name))));

result.isPresent();
// true

result.orElse(null);
// Employee{id=1, name='john'}
```

Optionalオブジェクトが保持する値がnullの場合は空のOptionalを返します。

```java
Optional<Long> optId = Optional.of(1L);
Optional<String> optName = Optional.ofNullable(null);

Optional<Employee> result = optId.flatMap(id -> optName.flatMap(name -> Optional.of(new Employee(id, name))));

result.isPresent();
// false

result.orElse(null);
// null
```

Optionalを返すFunctionをmapで使うと戻り値が期待しない型になってしまいます。

```java
Optional<Optional<String>> nullableName = employee.map(emp -> Optional.ofNullable(emp.getName()));
```


# [Java 9で追加されたAPI] (https://docs.oracle.com/javase/jp/9/docs/api/java/util/Optional.html)

## ifPresentOrElse

ifPresentのバリエーションが増えました。
Optionalオブジェクトが保持する値がnullの場合、引数に指定するRunnableの処理ブロックが実行されます。

```java
Optional<Employee> employee = Optional.ofNullable(null);

employee.ifPresentOrElse((e) -> {
    e.setName(e.getName().toUpperCase());
    System.out.println(e);
},
() -> {
    System.out.println("empty action");
    // empty action
});
```

## or

Optionalオブジェクトが保持する値がnullの場合、引数に指定するSupplierが生成したOptionalオブジェクトを返します。
Supplierがnullを返すと例外がスローされます。

```java
String str = null;
Optional<String> nonNullString = Optional.ofNullable(str).or(() -> Optional.of("nonNull"));

nonNullString.isPresent();
// true

nonNullString.get();
// nonNull
```

## stream

Optionalオブジェクトが保持する値が非nullの場合はその値だけを持つstreamを返し、nullの場合は空のstreamを返します。

```java
List<Optional<String>> list = List.of(
    Optional.of("a"),
    Optional.of("b"),
    Optional.of("c"),
    Optional.empty(),
    Optional.of("e"),
    Optional.empty(),
    Optional.of("g")
);

list.stream().filter(Optional::isPresent).map(Optional::get).forEach(System.out::println);
// a
// b
// c
// e
// g

// streamを使う場合
list.stream().flatMap(Optional::stream).forEach(System.out::println);
// a
// b
// c
// e
// g
```

# [Java 10で追加されたAPI] (https://docs.oracle.com/javase/jp/10/docs/api/java/util/Optional.html)

* モジュール: java.base
* パッケージ: java.util

## orElseThrow

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合はNoSuchElementExceptionをスローします。この動作はgetメソッドと同じです。
このため、Java 1.8からある同じメソッド名のorElseThrowのバリエーションの追加というよりも

```text:java1.8_orElseThrowのシグネチャ
public <X extends Throwable> T orElseThrow​(Supplier<? extends X> exceptionSupplier)
    throws X extends Throwable
```

getメソッド名から曖昧さを取り除いたgetメソッドの代わりになるメソッドという感じです。

```text:java1.8_getのシグネチャ
public T get()
```

orElseThrowはメソッド名から例外がスローされ得ることがわかります。

```text:java10_orElseThrowのシグネチャ
public T orElseThrow()
```

# [Java 11で追加されたAPI] ()

## isEmpty

```text:java11_isEmptyのシグネチャ
public boolean isEmpty()
```

値が存在しない場合にtrueを返します。

# [Java 12で追加されたAPI] (https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Optional.html)

追加されたAPIはありません。

# [Java 13で追加されたAPI] (https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/Optional.html)

追加されたAPIはありません。

# [Java 14で追加されたAPI] (https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Optional.html)

追加されたAPIはありません。


# その他のおさらいメモ

* [Java NIO2のおさらいメモ] (https://qiita.com/rubytomato@github/items/6880eab7d9c76524d112)
    * 2017年08月15日
* [クラス java.util.Objectsのおさらいメモ] (https://qiita.com/rubytomato@github/items/ba38877ed5a00dd24f16)
    * 2017年08月25日
* [Java Collections Frameworkのおさらいメモ] (https://qiita.com/rubytomato@github/items/554095ae21a2c36f131a)
    * 2017年08月30日
* [パッケージ java.time.temporal のおさらいメモ] (https://qiita.com/rubytomato@github/items/e9325dd46aa11f1b8e2e)
    * 2018年01月30日