JavaのOptionalのモナド的な使い方

`NullPointerException` 嫌いですよね！そんなときに頼りになるのが Java 8 から導入された `Optional` です。

でも、 `null` の代わりに `Optional` を積極的に使うとコードが `Optional` だらけになり、特に次のような場合に面倒くさいです。

1. `Optional<Integer> a` があるとき、 `a` の値を二乗したい。ただし、 `a` が `empty` の場合は `empty` を得たい。
2. `Optional<Double> a` があるとき、 `a` の平方根を計算したい。ただし、 `a` が `empty` または負の数の場合は `empty` を得たい。なお、 `Math.sqrt` を安全にした（負の数を渡すと `empty` を返す）関数 `Optional<Double> safeSqrt(double)` があるものとして考えて良い。
3. `Optional<Integer> a` と `Optional<Integer> b` があるとき、 `a + b` を計算したい。ただし、 `a` か `b` が `empty` の場合には `empty` を得たい。

本投稿では、このような場合の簡潔な書き方について説明します（本投稿は ["SwiftのOptional型を極める"](http://qiita.com/koher/items/c6f446bad54442a28bf4) と ["モナドについてSwiftで説明してみた"](http://qiita.com/koher/items/12f72f2fc2db7fa709cf) を Java 向けにアレンジしたものです）。

## map

> _1._ `Optional<Integer> a` があるとき、 `a` の値を二乗したい。ただし、 `a` が `empty` の場合は `empty` を得たい。

これを単純にやろうとすると次のようなコードになります。

```java
// ダメな例
Optional<Integer> a = Optional.of(3);
Optional<Integer> result;
if (a.isPresent()) { // empty でなければ
    Integer x = a.get(); // 中の値を取り出し
    result = Optional.of(x * x); // 二乗してから Optional で包み直す
} else {
    result = Optional.empty();
}
```

たかが整数を二乗するためだけに面倒すぎます。

`Optional` の `map` メソッドを使えば次のように書けます。

```java
a.map(x -> x * x)
```

この式は次のように働きます。

- もし `a` が `empty` でなければ `Optional` に包まれた中の値を取り出す。
  - 取り出された値を引数として `x` に渡す。
  - 計算された `x * x` を `Optional` で包み直して返す。
- もし `a` が `empty` なら `empty` を返す。

このように、 __`map` メソッドを使えばわざわざ `Optional` に包まれた値を取り出してから計算して包みなおさなくても、「二乗する」という操作を直接記述するだけで事足ります__。

実際に `a` が値を持つ場合と `empty` の場合に実行すると次のようになります。

```java
Optional<Integer> a = Optional.of(3);
Optional<Integer> result = a.map(x -> x * x); // Optional[9]
```

```java
Optional<Integer> a = Optional.empty();
Optional<Integer> result = a.map(x -> x * x); // Optional.empty
```

`map` という名前が `Stream` の `map` と同じなので気になる人もいるかもしれませんが、 `Stream` の `map` との関連については後ほど述べます。

## flatMap

> _2._ `Optional<Double> a` があるとき、 `a` の平方根を計算したい。ただし、 `a` が `empty` または負の数の場合は `empty` を得たい。なお、 `Math.sqrt` を安全にした（負の数を渡すと `empty` を返す）関数 `Optional<Double> safeSqrt(double)` があるものとして考えて良い。

この `safeSqrt` は次のように実装できます[^2]。

```java
static Optional<Double> safeSqrt(double x) {
    if (x < 0.0) {
        return Optional.empty();
    }

    return Optional.of(Math.sqrt(x));
}
```

見ての通り、 `safeSqrt` は引数 `x` が負のときに `empty` を返す他は、ただ `Math.sqrt` の結果を `Optional` に包んで返しているだけです。

### Optionalとエラー

このように、 __`Optional` はエラーを表すためにも使われます__。これまで、 `null` を `return` することでエラーを表すメソッドがあったように、 `empty` を `return` することでエラーを表すわけです。 __`null` でエラーを表すとチェックを忘れて `NullPointerException` を引き起こしがちですが、 `Optional` であれば `empty` である可能性が型で表されており、値を利用するためには明示的に取り出さないといけないのでより安全です__。

例えば、 `Stream<T>` の最初の要素を返す `findFirst` メソッド[^3]の戻り値の型は `T` ではなく `Optional<T>` です。 `Stream` に要素が存在すれば最初の要素を（ `Optional` に包んで）返しますが、一つも要素がなければ `empty` を返します。これは、 Java 8 以前から存在する `Deque<E>` （ `LinkedList` などのスーパータイプ）の `peekFirst` メソッド[^4]の戻り値が `E` なのとは対照的です。 `peekFirst` メソッドは要素がなければ `null` を返すので忘れずにチェックしなければなりません。

__検査例外でも安全にエラー処理ができますが、 `try`, `catch` は書くのが面倒なのと、式ではなく文になってしまうため計算の途中に組み込むことができません__。また、 `Optional` であればエラーという状態を値のまま扱うことができるため、それをフィールドに格納しておいて後から取り出すなど、 __エラーを値として取り回して任意のタイミングで（しかし忘れずに）エラー処理を行うことができます__[^5]。

### フラットにする

さて、本題に戻りましょう。

一見、この場合も `map` を使えば書けそうに思えます。

```java
a.map(x -> safeSqrt(x))
```

しかし、これではダメです。上記の式の結果の型は何になるでしょうか？

答えは、 `Optional<Double>` ではなく `Optional<Optional<Double>>` です。なぜなら、 `map` は `safeSqrt(x)` の戻り値をさらに `Optional` で包んで返してしまうので、二重に `Optional` に包まれてしまうわけです。

この場合、 `a` が `null` のときには外側の `Optional` が `empty` に、 `a` が負の数の場合には内側の `Optional` が `empty` になります。今やりたいことは、それらをフラットに潰して `Optional<Double>` にし、外と内のどちらか一方でも `empty` であれば `empty` にしてしまうことです。

これをやってくれるのが `flatMap` です。 `flatMap` は `map` とフラットに潰す処理をまとめてやってくれるメソッドです。 `Optional` に包まれた値に適用したい処理がエラーになる可能性があるなど（ `x * x` は失敗しないが `safeSqrt(x)` は失敗し得る）、 `Optional` に渡す処理の戻り値も `Optional` になってしまう場合には `flatMap` が使えます。

```java
a.flatMap(x -> safeSqrt(x))
```

概念的には、これは `map` をしてから二重になった `Optional` を平らにする（ `flatten` ）という処理です。

```java
// ※ このコードは概念を表したものであり、正しい Java のコードではありません。
a.map(x -> safeSqrt(x)).flatten() // map すると二重になったのでフラットにする
```

なお、 Java には `flatten` はないですが（というか `Optional` のインスタンスメソッドとしては Java の構文の限界で適切に宣言できない）、 `flatten` 相当の処理は次のようにして実現できます。

```java
Optional<Optional<Integer>> nested = Optional.of(Optional.of(42));
Optional<Integer> flattened = nested.flatMap(x -> x); // Optional[42]
```

`a` が正の場合、負の場合、 `empty` の場合に `a.flatMap(x -> safeSqrt(x))` を実行すると、次のように望んだ結果が得られます。

```java
Optional<Double> a = Optional.of(2.0);
Optional<Double> result = a.flatMap(x -> safeSqrt(x)); // Optional[1.4142135623730951]
```

```java
Optional<Double> a = Optional.of(-2.0);
Optional<Double> result = a.flatMap(x -> safeSqrt(x)); // Optional.empty
```

```java
Optional<Double> a = Optional.empty();
Optional<Double> result = a.flatMap(x -> safeSqrt(x)); // Optional.empty
```

## 複数のOptional

> _3._ `Optional<Integer> a` と `Optional<Integer> b` があるとき、 `a + b` を計算したい。ただし、 `a` か `b` が `empty` の場合には `empty` を得たい。

これを愚直にやると次のようになります。

```java
Optional<Integer> a = Optional.of(2);
Optional<Integer> b = Optional.of(3);
Optional<Integer> result;
if (a.isPresent()) {
    if (b.isPresent()) {
        result = Optional.of(a.get() + b.get());
    } else {
        result = Optional.empty();
    }
} else {
    result = Optional.empty();
}
```

足し算をするためだけにこれは耐えられません。

このようなケースにも、 `flatMap` と `map` を組み合わせて使うことで対応できます。

```java
a.flatMap(x -> b.map(y -> x + y))
```

イメージとしては、 `flatMap` と `map` をネストすることで `Optional` に包まれていない世界をつくり（ `Optional<Integer> a` と `Optional<Integer> b` を `Integer x` と `Integer y` として扱えるようにし）、 `x + y` を計算するという感じです。計算結果は `Optional` に包まれますが、外側が `flatMap` なので二重に包まれてしまうことはありません。

実行結果は次の通りです。 `a` と `b` の片方でも `empty` なら結果は `empty` となります。

```java
Optional<Integer> a = Optional.of(2);
Optional<Integer> b = Optional.of(3);
Optional<Integer> result = a.flatMap(x -> b.map(y -> x + y)); // Optional[5]
```

```java
Optional<Integer> a = Optional.empty();
Optional<Integer> b = Optional.of(3);
Optional<Integer> result = a.flatMap(x -> b.map(y -> x + y)); // Optional.empty
```

### 処理が失敗しうる場合

`x + y` という失敗しない処理なので、上記のコードでは内側が `map` になっていますが、失敗しうる処理であれば `flatMap` を入れ子にする必要があります。

例えば、 `safeSqrt` と同じように安全な `Optional<Double> safePow(double x, double y)` を考えます[^6]。その場合、 `Optional<Double> a` と `Optional<Double> b` に対して `safePow` を計算するには次のようにします。

```java
a.flatMap(x -> b.flatMap(y -> safePow(x, y)))
```

### 三つ以上のOptional

`Optional` の値が三つ以上になってもその分ネストするだけで対処できます。

例えば、 `Optional<Integer> a`, `Optional<Integer> b`, `Optional<Integer> c` の和を求める計算は次のように書けます。

```java
a.flatMap(x -> b.flatMap(y -> c.map(z -> x + y + z)))
```

もちろん、処理の結果が `Optional` になる場合には一番内側の `map` を `flatMap` にしないといけません。

## コレクションとしてのOptional

`Optional` は要素が 0 個か 1 個の場合しかないコレクションと考えることもできます。

このことは次の二つのコードを見比べればよくわかります。前者は `Optional` で書いたもの、後者は同じことを `Stream` で書いたものです。

```java
Optional<Integer> a = Optional.of(3);
Optional<Integer> b = a.map(x -> x * x); // Optional[9]

Optional<Integer> c = Optional.empty();
Optional<Integer> d = c.map(x -> x * x); // Optional.empty

Optional<Integer> e = Optional.of(2);
Optional<Integer> f = Optional.of(3);
Optional<Integer> sum = e.flatMap(x -> f.map(y -> x + y)); // Optional[5]
```

```java
Stream<Integer> a = Stream.of(3);
Stream<Integer> b = a.map(x -> x * x); // [9]

Stream<Integer> c = Stream.of();
Stream<Integer> d = c.map(x -> x * x); // []

Stream<Integer> e = Stream.of(2);
Stream<Integer> f = Stream.of(3);
Stream<Integer> sum = e.flatMap(x -> f.map(y -> x + y)); // [5]
```

そっくりですね！

厳密には `Stream` はストリームとして一度だけ値を取り出すことしかできずコレクションではないですが、イメージとしては↑で伝わると思います。

### filter

`Stream` には `filter` というメソッドがあります。 `filter` を使えば、条件にマッチする要素だけを取り出すことが簡単にできます。

例えば、 `Stream<Integer>` から偶数の要素だけを取り出すには、 `filter` に `x -> x % 2 == 0` （ 2 で割った余りが 0 ）を渡します。

```java
Stream<Integer> a = Arrays.asList(1, 2, 3, 4, 5).stream(); // [1, 2, 3, 4, 5]
Stream<Integer> result = a.filter(x -> x % 2 == 0); // [2, 4]
```

`Optional` も `filter` メソッドを持っています。これは、 `Optional` を要素が 1 個 か 0 個のコレクションと考えて自然な挙動をします。

例えば、 `[2]` （一つの要素 `2` だけを持つコレクションを意図）に対して先程の `filter` を実行すると `2` は偶数なので `[2]` が返されますが、 `[3]` だと `[]` （空のコレクション）になってしまいます。また、 `[]` に対して偶数かどうかで `filter` しても、最初から要素がないので当然結果は `[]` です。

`Optional` の `filter` は、このように考えたときと同じように動きます。

```java
Optional<Integer> a = Optional.of(2); // [2] に相当
Optional<Integer> result = a.filter(x -> x % 2 == 0); // Optional[2]
```

```java
Optional<Integer> a = Optional.of(3); // [3] に相当
Optional<Integer> result = a.filter(x -> x % 2 == 0); // Optional.empty
```

```java
Optional<Integer> a = Optional.empty(); // [] に相当
Optional<Integer> result = a.filter(x -> x % 2 == 0); // Optional.empty
```

### ループ

コレクションと言えばループです。 Java 8 からは _拡張 for 文_ だけでなく `forEach`
 メソッドが使えます。

例えば、次のようにして `List` の要素を表示することができます。

```java
List<Integer> a = Arrays.asList(2, 3, 5, 7, 11);
a.forEach(x -> System.out.println(x));
```

実行結果は次の通りです。

```
2
3
5
7
11
```

なお、 `println` するだけであれば次のように `forEach` メソッドに直接 `println` を渡すこともできます。

```java
a.forEach(System.out::println);
```

`Optional` に `forEach` メソッドはないですが、同じことをしてくれるのが `ifPresent` メソッドです。

`ifPresent` メソッドは、 `Optional` が値を持っている場合のみ、引数に渡した処理を実行するメソッドですが、 `Optional` をコレクションだと考えるとこれは `forEach` に当たります。

次のコードを実行すると `2` が表示されます。

```java
Optional<Integer> a = Optional.of(2); // [2] に相当
a.ifPresent(System.out::println);
```

しかし、次のコードでは要素がないコレクションの `forEach` と等価なため、何も表示されません。

```java
Optional<Integer> a = Optional.empty(); // [] に相当
a.ifPresent(System.out::println);
```

残念ながら `Optional` は `Iterable` を実装していないので、 _拡張 for 文_ で使うことはできません。

#### ifPresentとisPresent+get

`ifPresent` を使うのと、 `isPresent` で分岐してから `get` で値を取り出すのでは似たようなことができます。

しかし、 `isPresent` + `get` は、本当に `isPresent` でチェックした上で `get` を呼んでいるかコンパイル時にチェックすることができません。もし `empty` に対して `get` を呼び出すと実行時エラー（ `NoSuchElementException` ）になってしまいます。 `ifPresent` であればそのような心配は必要ないので、 __`isPresent` + `get` よりも `ifPresent` を使うことをオススメします__。

## モナドとしてのOptional

本投稿のタイトルは "JavaのOptionalのモナド的な使い方" ですが、 ___モナド___ とは何でしょうか？

実は `map` と `flatMap` を使うというのが「モナド的な使い方」の意味するところです。前節で `Optional` と `Stream` の類似性を見てもらいました。 `Optional` と `Stream` の `map` と `flatMap` が同じ意味を持つことがわかったと思います。その共通性がモナドの持つ性質です。  __モナドとは、 `map` や `flatMap` を持つ存在を抽象化したものです__。

しかし、 `map` や `flatMap` を持っていたら何でもモナドと呼べるわけではありません。いきなり `return null` するとかいう実装だと、とても「共通」の性質を持つわけがないですよね。モナドであるためには、 ___モナド則___ と呼ばれるルールを満たさなければなりません。

`Optional` を使う上では知らなくても特に問題はないですが、せっかくなので __モナドとは何か__ についてももう少し正確な説明をします。モナドは関数型言語でよく用いられる概念です。モナドについて調べると大抵 ___モナド則___ が出てきますが、肝心の記述が関数型言語で書かれていてわからん！となることが多いんじゃないかと思います。本節では、__モナド則についても Java の構文で記述します__。ただし、ややこしいだけなので `? extends` のようなワイルドカードは省略します。

### モナドとは

`Foo<T>` が次の条件を満たすとき、 `Foo<T>` はモナドです。

- `Optional` の `of` のように、単一の `T` 型の値を包んで `Foo<T>` を返す静的メソッドまたはコンストラクタを持つ。
- `<U> Foo<U> flatMap(Function<T, Foo<U>>)` というメソッドを持つ。
- `flatMap` の実装が ___モナド則___（後述）を満たす。
- `Foo<T>` が ___ファンクター___（後述）である。

ざっくりと言えば、適切に実装された（モナド則を満たした） `flatMap` を持った型はモナドと言えるでしょう（モナドはファンクターでもあるので `map` も持っている必要がありますが）。

#### モナド則

- `Foo.of(x).flatMap(x -> f(x)) == f(x)` が成り立つ。
- `foo.flatMap(x -> Foo.of(x)) == foo` が成り立つ。
- `foo.flatMap(x -> f(x).flatMap(y -> g(y))) == foo.flatMap(x -> f(x)).flatMap(y -> g(y))` が成り立つ。

モナド則は、中身をじっくり見てみればわかりますが、ごく当たり前に満たすべき性質を言ってるだけです。言ってみれば、積の結合法則 `(a * b) * c == a * (b * c)` のモナド版のようなものです。
例えば、最初の法則は `x` を `Foo` で包んでからやっぱり中身の `x` を取り出してメソッド `f` を適用した結果は、直接 `f` を `x` に適用した結果と等しいという意味です。要するに、 `of` で値を包むときや `flatMap` で取り出すときに余計なことをするなというだけです。

積の結合法則を満たさなければ数とは言えないというのと同じように、モナド則を満たさなければモナドとは言えないという当然の性質を述べているに過ぎません。自作の `Number` クラスに結合法則が成り立たないような（ `*` の代わりの） `multiply` メソッドを実装することはできますがそれが意味を持たないのと同じように、モナド則を満たさないモナドっぽい型を実装することはできますがそれはナンセンスなのです。

他の二つについても、中身をじっくり見てみればそれが何を意味するのかわかると思いますし、当然満たすべきものであることがわかると思います。

### ファンクターとは

前述の通り、モナドはファンクターでないといけません。ファンクターとは何でしょうか。

`Foo<T>` が次の条件を満たすとき、 `Foo<T>` はファンクターです。

- `<U> Foo<U> map(Function<T, U>)` というメソッドを持つ。
- 上記の実装が ___ファンクター則___（後述）を満たす。

同じくざっくりと言えば、適切に実装された `map` を持った型はファンクターと言えるでしょう。

#### ファンクター則

次のような、引数で受けた値を返すだけのメソッド `id` があるとします。

```java
static <T> id(T x) {
    return x;
}
```

そのとき、ファンクター則は次のように書けます。

- 恒等メソッド `id` （後述）に対して、 `foo.map(x -> id(x)) == id(foo)` が成り立つ。
- `foo.map(x -> g(f(x))) == foo.map(x -> f(x)).map(y -> g(y))` が成り立つ。

ファンクター則もモナド則同様、じっくり見れば当然満たすべきものだとわかると思います。

## まとめ

`Optional` は憎き `NullPointerException` と戦うための強力な武器です。でも、 `Optional` に包まれた値を扱おうとすると少し面倒なことがあります。

そんなときには、 `map` や `flatMap` のようなモナド的なメソッドを使えばコードを簡潔に書けることがあります。 `map` や `flatMap` を習得して快適な `Optional` ライフを送りましょう！

## おまけ：Optionalと変性

[去年の Advent Calendar では Java のジェネリクスと変性について書きました](http://qiita.com/koher/items/7dea63e0ce52ebda9873)。

`Optional` は大抵の場合、共変として問題ないので、（特にメソッドの引数や戻り値にする場合には） `Optional<? extends Foo>` の形で使うのがいいと思います。

```java
// 非変の場合（ Cat は Animal のサブクラスとする）
Optional<Cat> cat = Optional.of(new Cat());
Optional<Animal> animal = cat; // コンパイルエラー
```

```java
// 共変の場合（ Cat は Animal のサブクラスとする）
Optional<? extends Cat> cat = Optional.of(new Cat());
Optional<? extends Animal> animal = cat; // OK
```

------------------------------

[^2]: `NaN` のことを考えると `!(x >= 0.0)` の方が適切です。

[^3]: Javadoc は[こちら](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#findFirst--)。

[^4]: Javadoc は[こちら](https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html#peekFirst--)

[^5]: 例外と比較した場合の `Optional` の欠点はエラーの理由を取得できないことです。 `Optional` がよく使われる関数型言語などでは、そういう場合は `Either<L, R>` のような `L` か `R` のどちらかを保持することができる型を使って、値かエラーかを保持することが行われます。残念ながら Java 8 時点では標準ライブラリで `Either` 相当のクラスは提供されていません。

[^6]: 例えば、 $-1.0^{0.5}$ などは実数の範囲で解を持ちません。