Optionalの使い方

Java SE 8から登場したjava.util.Optionalの基本的な使い方。

執筆時バージョン
Java

Java SE 8

概要

Optionalクラス図
Figure 1. Optionalクラス図

Java8より登場。Optionalは値(参照)を保持するラッパーで、値を取り出すメソッドをいくつか提供する。値を取り出すとき、それがnullの場合の挙動が選べる。本来であればnullチェックして○○するが必要であったが、Optionalならメソッドを指定するだけでよい。nullチェックも含めてメソッド内部で行っている。

Optionalは戻り値でよく使われる。便利なのであらゆるところで使いたくなるが、使いすぎに注意する。どこで使うべきなのかはこちらにまとめた。

その他の注意点は次の通り。

  • イミュータブルであること。

  • ファクトリメソッドがあるのでnewしない(できない)。

  • 値の取り出し方は独特といえば独特なので慣れる。

  • 値が取り出しに慣れてくればmap,filterあたりも使う。

生成

3つのファクトリメソッドのいずれかから生成する。

メソッド 備考

of(T value)

Optionalを生成。値がnullの場合はNullPointerException。

ofNullable(T value)

Optionalを生成。値がnullの場合は空のOptional。

empty()

常に空のOptional。

NullPointerExceptionにならないからといって何も考えずにofNullable()を利用してはいけない。本来nullになってはいけない場合にof()を使っておけばnullチェックになる。もちろん自然にnullが考えられる場合はofNullable()を使う。

値を取り出す

この組合せは避ける

初めはやってしまいがちだが…、

Person person = null;
if (optional.isPresent())
  person = optional.get();

これであれば、次のようにする。

Person person = optional.orElse(null);

orElse(),orElseThrow()辺りから検討するのがよい。

メソッドを使って取り出す

Optionalで値を取り出すときは、次の4つのメソッドを使う。それぞれ値が存在しなかったときの振る舞いが違うので、それによってメソッドは必然的に決まる。

メソッド 値が存在する場合 値が存在しない場合

get()

値を返す。

NoSuchElementException

orElse(T other)

値を返す。

指定された値を返す。

orElseGet(Supplier<? extends T> other)

値を返す。

指定されたsupplierから生成した値を返す。

orElseThrow(Supplier<? extends X> exceptionSupplier)

値を返す。

指定されたsupplierから生成した例外を投げる。

次のことに注意する。

  • get()は値がなかった場合はNoSuchElementException。
    NullPointerExceptionではない。

  • orElse()とorElseGet()は似ているが違う。
    orElseGet()の方はSupplierから値を生成するので遅延実行になる。

map,flatMap,filter,ifPresent

String personName = optional.map(Person::getName)
                            .orElse("");

Streamの操作のようなことがOptionalでもできる。もちろんOptionalの中身がnullでもそれなりにうまく動くので、1度値を取り出す手順が不要。Consumer<T>を受け取るメソッドはforEach()ではなくifPresent()。

OptionalInt,OptionalLong,OptionalDouble

OptionalInt,OptionalLong,OptionalDoubleクラス図
Figure 2. OptionalInt,OptionalLong,OptionalDoubleクラス図

これらのクラスはプリミティブに対応したOptional。Optional<T>では参照しか扱えないので、プリミティブの値をそのまま使えるようにしてある。継承関係などはないが基本的な使い方やメソッド名は規則性がある。

Appendix B: 改訂履歴

  • v1.0, 2014-11-08: 初稿