JavaのOptionalを戻り値に使用することについて消極的な理由
僕は戻り値にOptional
を使用することに消極的です。
戻り値に使用する理由に対して以下の理由をよく聞きます。
- メソッドを利用した際にnull値を返す可能性を明示する。
- nullを考慮したコーディングを強制させる。
これらをやる理由が無いと考えているからです。
メソッドを利用した際にnull値を返す可能性を明示する。
これ本当に明示できているのでしょうか?
Optional
だから明示できているのでしょうか?
Object
でもnull
が入る可能性があるのだから、Object
でもnull
を返す可能性は考えられるのでは無いでしょうか?
以下の条件で使い分けるのだとするなら、Optional
を使用する利点が出てくると思います。
Optional
を返すメソッドではnull
を返す可能性がある。Optional
を返さないメソッドはnull
を返す可能性が無い。
ただし、戻り値から値を取り出す場合にコーディングに差異が出てきます。
id
と一致するオプションが無い場合Optional
を返すメソッドを例とします。
public Optional<OptionDetail> fetch(Integer id) { if (id == 1) { OptionDetail optionDetail = new OptionDetail().setId(id).setName("SAMPLE"); return Optional.of(optionDetail); } return Optional.ofNullable(null); }
このとき呼び出し元は以下のように実装します。
OptionDetail optionDetailA = fetchDetailA(1) .orElseThrow(() -> { System.out.println("log message"); throw new IllegalArgumentException("invalid id."); }); optionDetailA.getId();
データがない場合はログを出して、例外を出して処理を終えます。
.get()
やorElse(T)
を利用しないのは、null
というのは、データがない状態を示しているからです。
データが無いのに、その場合の値を置き換えるとかおかしいですよね?
.get()
を使用した場合、値がnull
だった場合にNoSuchElementException
が発生します。
次にOptional
を使用しない場合です。
public OptionDetail fetchDetailB(Integer id) { if (id == 1) { OptionDetail optionDetail = new OptionDetail().setId(id).setName("SAMPLE"); return optionDetail; } return null; }
このとき呼び出し元は以下のように実装します。
OptionDetail optionDetailB = fetchDetailB(1); if (Objects.isNull(optionDetailB)) { System.out.println("log message"); throw new IllegalArgumentException("invalid id."); } optionDetailB.getId();
見ればわかると思うのですが、対して違いが無いんです。
個人的には戻り値が全部Optional<T>
となっているよりObject
となっていた方が良いと思ったり、でもいちいちif文を書くの面倒だなとも思います。
そもそもを語るのなら、null
を返すメソッドはNullPointerException
を発生させる可能性があるため避けるべきです。
それを考慮した場合のメソッドは以下のようになるでしょう。
public OptionDetail fetchDetailC(Integer id) throws IllegalArgumentException { if (id == 1) { OptionDetail optionDetail = new OptionDetail().setId(id).setName("SAMPLE"); return optionDetail; } throw new IllegalArgumentException("invalid id."); }
データがない場合に例外を出します。 「存在しないデータを取得しようとした」という意味です。
利用側では以下の実装になります。
OptionDetail optionDetailC; try { optionDetailC = fetchDetailC(1); } catch (IllegalArgumentException e) { System.out.println("log message"); throw e; } optionDetailC.getId();
Optional
の場合も同じ様な実装になります。
OptionDetail optionDetailD; try { optionDetailD = fetchDetailD(1).get(); } catch (IllegalArgumentException e) { System.out.println("log message"); throw e; } optionDetailD.getId();
どちらも同じ様な実装になるので、どっちでもいいんですよ。
ただ、Optional
の場合はorElse
やorElseThrow
を利用できないので利用する必要性がありません。
また、fetchしてから一度.get()
しないとなりません。
なにかデータを取得するメソッドを実行しているのに、なぜ何かを取得するメソッド(.get()
)を再度実行するのでしょうか?
IDEによってはisPresent()
を利用してくださいと警告がでて混乱する可能性があるので使わないほうが良いでしょう。
これを考えると、この場合はOptional
を使わない方がマシです。
結論
Optional
の利用云々によってコーディングは対して違いがない。null
を返さない実装の場合はOptional
は処理を煩雑にするため使用しない。- そもそも
null
を返す実装を疑い、メソッドの利便性を考えたときにOptional
を使うメリットは小さい
nullを考慮したコーディングを強制させる。
本当にnull
を考慮したコーディングを強制させるのでしょうか?
僕はそんなことは無いんじゃないかと思ってます。
.get()
した場合try-catch
を書かなくてもコンパイルは通ります。
そのままデプロイした場合NoSuchElementException
が発生する可能性があります。
それはNullPointerException
と何が違うのでしょうか。
「Optional
を返すということはnull
を返す可能性があると考えられるんだ!」
「だから.get()
ではくorElse()
かorElseThrow()
を使用しろ!」
orElse
を利用するなら、なぜデフォルト値をメソッド側が返さないのでしょうか?
orElseThrow
を利用するなら、なぜメソッド側でIllegalArgumentException
などの例外を出さないのでしょうか?
それはOptional
を利用するメリットかもしれませんが、Optional
を使わなければならない理由にはなりません。
だからOptional
についての議論が起こったりするんでしょうね。
null
を返すことに理由がある場合、なぜnull
を返すのかjavadocにかかれているはずです。
そうなるとnull
を返す可能性があるからと言ってjavadocすら確認しないということは無いでしょう。
そこに重要な情報が書かれていた場合のことを考えると、戻り値だけを見てコーディングするのは危険です。
(処理内容をコードから読み解く必要性はないです。必要がある場合はメソッド名が明確ではありません。)
また、null
を返すことに理由がない場合はそのメソッドの見直しが必要です。
理由のないnull
返却は開発者を混乱させます。
最終的には利用するメソッドがどんな条件でnull
や例外を出すのか確認して実装することになると思います。
そうなった場合、コーディング時のメソッドの使い方を確認するコストに差異はありません。
そして、それを確認したときOptional
を使用していなくても、エンジニアはそれに適した実装をします。
結論
- nullを考慮したコーディングを強制するわけではない。
Optional
を利用してもしなくてもコーディング時にやることに変わりはない。
最後に
以上の理由から僕はOptional
を利用することに消極的です。
Optional
はメソッドを利用する際の処理を煩雑にしますし、実装方法によっては開発者を混乱させます。
また、javaの場合古い書き方に慣れている人のほうが絶対数が多く、Optional
の実装になれていない可能性があります。
チーム内で使い方の議論をして時間を浪費するぐらいなら使わない方が良いです。
そんなことよりも、よりよい機能について提案したり、リファクタリング作業や、業務の効率化にリソースを使ったほうが良いです。
Optional
の利用について議論をしていたり、考えている方の参考になれば幸いです。