JavaのOptional型の利用方針

エキサイト株式会社メディア開発の佐々木です。

メンバーもJavaの開発に慣れてきて、今まで触ってきた言語にはない機能だったり仕組みだったりに格闘している日々です。今日は、Optionalについてです。

Optionalとは

Javaは、nullを許容しているレガシー言語です(笑)Optional型は、値がnullかどうかわからないものをくるんでくれる型になります。nullにオブジェクトとしてアクセスしてしまうとNullPointerExceptionが発生していますので、nullかどうかわからないものには有用です。Optionalにはいくつかのメソッドが実装されています。

データ取得系

Optionalには、取得系と処理系のメソッドが実装されています。

  • get()

値を取得します。nullの場合に例外を投げます。

Optional<String> optional = Optional.of("sample");
String s = optional.get();     // Nullだと NoSuchElementExceptionを投げます
  • orElse()

値を取得して、nullの場合に返す値も設定します。orElseの中は、nullじゃなくても実行されます。

Optional<String> optional = Optional.of("sample");
String s = optional.orElse("other");     // 必ずorElseが実行されてotherが設定されて、nullだったら設定された値が返る
  • orElseGet()

値を取得して、nullの場合に返す値も設定します。上記との違いは、nullだったときに、ラムダ式が実行されている点です。nullのときに返却する処理が重い場合は、こちらを選択する方がいいでしょう。

Optional<String> optional = Optional.of("sample");
String s = optional.orElseGet(() -> "other"); // nullだったときだけ、ラムダ式が実行され"other"が返る
  • orElseThrow

値を取得できなかったら例外を設定してthrowします。

Optional<String> optional = Optional.of("sample");
optional.orElseThrow(() -> new RuntimeException("no value"));

処理系

こちらは戻り値がない処理系になります。

  • ifPresent

値があるときだけ、処理するメソッドになります。

Optional<String> optional = Optional.of("sample");
optional.ifPresent(e -> System.out.println(e));
  • ifPresentOrElse

値があるときとなかったときの処理をそれぞれ書く必要があります。

Optional<String> optional = Optional.of("sample");
optional.ifPresentOrElse(e -> System.out.println(e), () -> System.out.println("no value"));

利用箇所

Optionalは通常の型ですので、どこでも使えます。が、使う場所は選んだほうが良いと思います。

  • メソッドの戻り値
    public Optional<String> getOptionalName(){
       // 処理
    }

ここはメソッドでOptionalが返却されるということがわかっています。なんで、Optionalが返却されるかというと、このメソッドでは、 orElse() の判断がつかないからということになります。メソッドの戻り値にOptionalを使うのは有用かなと思います。

  • メソッドの引数

Javaにはオーバーロードがあるので、それで呼び分けで良いとおもいます。わざわざOptionalの生成をおこなったりするのも面倒です。

    public Optional<String> getOptionalName(Optional<String> op){
       // 処理
    }
  • インスタンスフィールド

Optionalは、Serializableではないのでインスタンスフィールドには使用しない方がよさそうです。

class Data {
    
    ...
    Optional<String> optionalName;   // やってないけない
    ...

}
  • ローカル変数

わざわざOptionalを生成するのは手間が無駄だとおもいます。大きいメソッドの場合はあるかもですが、そもそも大きいメソッドを作るべきではありません。

おわりに

OptionalはNull許容なレガシー言語であるJavaにとっては、かなり有用な型になりますが、使いどころのメンバーと認識合わせはしておいた方がよさそうです。どこでも使えますけど、有効な使用箇所はメソッドの戻り値くらいかなと思います。