技術開発日記

技術やら日々思ったことを綴ってます。

Java8のOptionalの使い所

そもそもOptionalとは

OptionalはT型のオブジェクトに対するラッパーで、オブジェクトがnullかどうかを判断したり、nullだった場合のデフォルト値を設定できるJava8から追加されたクラス。
Nullオブジェクトに近い感じでしょうか。

どういったところで使うのか

・Streamメソッドの返却値としてOptional型を返すのがいくつかあるので(findFirst,findAny,min,max,flatMap,etc...)
その返却値に対して処理を追加したいとき。

メソッドの返却値がnullである可能性を明示的に示したいとき。

・煩わしいnullチェックの処理を除きたいとき。

・NullPointerExceptionのハンドリングに対して強いコードを書きたいとき。

Optionalの使用例

Optional#isPresent サンプルコード

public static void main(String[] args) {
    Optional<String> opt = Optional.ofNullable(doSomething());

    if (opt.isPresent()) {
        System.out.println("It's not null !!");
    }
}

static String doSomething() {
    return null;
}

これだと普通にnullチェックをしているのと変わらないので、こういった使い方はあまりよくなさそうです。
そこで、下記のように修正。
Optional#ifPresent サンプルコード

public static void main(String[] args) {
    Optional<String> opt = Optional.ofNullable(doSomething());

    opt.ifPresent(s -> System.out.println("It's not null !!"));
}

static String doSomething() {
    return null;
}

劇的ではないにしろ、少しスッキリしました。

他にもいろいろと便利なメソッド

nullの場合にデフォルト値を設定することができる Optional#orElse
サンプルコード

public static void main(String[] args) {
    // optionalの値がnullの場合
    Optional<String> opt = Optional.ofNullable(doSomething());
    String str = opt.orElse("Default");
    System.out.println(str); // Default
    
    //optionalの値がnullでない場合
    Optional<String> opt2 = Optional.ofNullable(doSomething2());
    String str2 = opt2.orElse("Default");
    System.out.println(str2); // Done something
}

static String doSomething() {
    return null;
}

static String doSomething2() {
    return "Done something";
}


nullの場合にデフォルト値を設定する"関数"を引数に設定することができる Optional#orElseGet

サンプルコード

public static void main(String[] args) {
    // optionalの値がnullの場合
    Optional<String> opt = Optional.ofNullable(doSomething());
    String str = opt.orElseGet(() -> "Default");
    System.out.println(str); // Default
    
    //optionalの値がnullでない場合
    Optional<String> opt2 = Optional.ofNullable(doSomething2());
    String str2 = opt2.orElseGet(() -> "Default");
    System.out.println(str2); // Done something
}

static String doSomething() {
    return null;
}

static String doSomething2() {
    return "Done something";
}


Optionalの値をfilterする
Optional#filterサンプルコード

public static void main(String[] args) {
    // optionalの値をfilter
    Optional<String> opt3 = Optional.ofNullable("abc");
    // "a"で始まる文字列のみ抽出
    opt3.filter(x -> x.startsWith("a"));
    String str3 = opt3.orElseGet(() -> "Default");
    System.out.println(str3); // abc


Streamメソッドを使ってのOptional 
サンプルコード

    public static void main(String[] args) {
        // listの最初の文字列を表示
        List<String> list = Arrays.asList("a", "b", "c");
        Optional<String> opt = list.stream().findFirst();
        opt.ifPresent(s -> System.out.println(s)); // a

        // listの最大の数値を取得
        List<Integer> list2 = Arrays.asList(1, 2, 3);
        Optional<Integer> opt2 = list2.stream().max(Comparator.naturalOrder());
        opt2.ifPresent(s -> System.out.println(s)); // 3
    }

まとめ

上記メソッド以外にもいろいろとメソッドがあって、全部を全部使うということはないと思うけど、いろんなパターンを自分のローカルで試したりするとなかなか面白いです。
ひとまず、Optionalを使うときは#isPresentや#getを使わないのが良さそうなので、そこだけ気をつければ今後ヌルポやnullチェックには悩まされたりすることが少なくなるのかもしれない。


参考
http://www.ne.jp/asahi/hishidama/home/tech/java/optional.html
http://mike-neck.hatenadiary.com/entry/2014/10/05/211758
http://www.javazuki.com/articles/javase/optional-usage.html
http://d.hatena.ne.jp/nowokay/20130524
http://enterprisegeeks.hatenablog.com/entry/2014/07/28/094300