Java8でnullではなくOptional型を利用する

以前の記事でもちょっと登場したんですが、Java8ではラムダ式に加えてOptional型というものが導入されました。

Optional型とは?

Optional型、言語によってはMaybeだったりOptionだったりOptionalだったり呼び方は色々なんですが、値が帰ってこない可能性のある返り値を表現する場合に用いられます。

値をこれでラップすることで直接いじることを禁止し、それによって「値が返ってこないかもしれない」ことを前提にしたプログラムの構築を構文上強制するところにメリットがあります。要するに、nullチェックを強制させるための構文(クラス)ですね。

どう使うの?

まず、一番大事なOptional型が返された場合の処理を考えます。返ってきたOptional型の基本的な利用の仕方としてはifPresentmaporElseなどがあります。

(例)

Optional<String> opt = optionalFunction();

opt.ifPresent(value -> {
  println(value);
});

Optional<String> mapped = opt.map(value -> {
  return "-" + value;
});

String result = opt.orElse("default string");

ifPresentは、Optional型のオブジェクトが値を持つ場合のみ、引数として渡されたラムダ式を実行します。引数にとるラムダ式はConsumer型なので値を返すことはできません。たとえば上記の例で言うと、optが値を持つ場合にはその値がコンソールに出力されることになります。もしoptが値を持っていなかった場合、何も出力されません。

mapは、Optional型のオブジェクトが値を持つ場合のみ、その中身の値に対して引数として渡されたラムダ式を適用し、その結果得られた値をOptional型でラップして返却します。もし値を持っていなかった場合にはNoneのままです。上記の例で言うと、optが値を持つ場合には、optの値の文字列の先頭に”-“を加えた文字列をOptionalで再度ラップし、mappedに代入します。

orElseは、Optional型のオブジェクトが値を持つ場合にはその中身の値を返し、値を持たない場合には引数として渡された値を返します。ちょうど入力窓に何も入力が無い場合にはデフォルト値をとりあえず放り込んでおく、という処理のようにデフォルト値を用意して処理する場合に便利です。なお、デフォルト値として渡す値について遅延ロードしたい場合(たとえばデフォルト値の生成にコストがかかる場合など)のために、orElseGetという、デフォルト値を生成するラムダ式を引数に取ることのできるメソッドも存在します。

ちなみに、nullではないことがほぼ確定してるのでスルーしたいという場合には、一応getという単純にOptionalが保持している値を返すメソッドも存在します。

どうやって生成するの?

Optional型を生成するには、ofNullableメソッドを利用します。

String hoge = null;
if(input > 5) {
  hoge = "input is more than 5";
}
return Optional.ofNullable(hoge);

これで「値が返ってこないかもしれないメソッドだよ!」ということを型情報によって対外的に発信できるようになりました。

nullチェック忘れはプログラムでは往々にしてあることですが、このエラーへの対処の難しさは実行時にしかエラーを吐いてくれないところにあります。これを構文レベルで解決できるようにしてしまうための1つの方法として、Optionalは非常に便利です。NullPointerExceptionを見たくないみなさんには是非使っていただきたいと思います。

参考