2つのOptionalで分岐する

僕のOptional<>の使い方がカッコワルイ。 - 谷本 心 in せろ部屋にある最後の例ですが、 2つのOptionalの組み合わせによって処理を分岐させるコードが幾つか載っています。 ifで書いた例を見てみましょう。

public String hello(Optional<String> name1, Optional<String> name2) {
    if (name1.isPresent()) {
        if (name2.isPresent()) {
            return call(name1.get(), name2.get());
        } else {
            return call1(name1.get());
        }
    } else {
        if (name2.isPresent()) {
            return call2(name2.get());
        } else {
            return call();
        }
    }
}

まとめると、こんな感じでしょうか。

name1 name2 呼び出すメソッド
値有り 値有り 2引数call
値有り Empty call1
Empty 値有り call2
Empty Empty 0引数call

これ、F#だったらmatch式を使えば分かりやすく書けます。

let hello name1 name2 =
  match name1, name2 with
  | Some name1, Some name2 -> call(name1, name2)
  | Some name1, None -> call1(name1)
  | None, Some name2 -> call2(name2)
  | None, None -> call()

JavaOptionalにもしmatchメソッドが実装されていれば、こんな感じに書けるんですけどね。

public String hello(Optional<String> name1, Optional<String> name2) {
    return name1.match(
        n1 -> name2.match(n2 -> call(n1, n2), () -> call1(n1)),
        () -> name2.match(n2 -> call2(n2), () -> call())
    );
}

Optionalのような型を導入するのであれば、やはりmatch式のようなもの*1が欲しくなりますね、という話でした。

*1:あとついでにモナド用の構文も・・・