戻り値にnullが含まれる場合があるかどうか微妙なメソッドを気づかず構築し、そのまま放置してしまうと思わぬエラーで苦しめられることもあります。
今回はこのような事態を未然に回避する方法の一つでもある「Optionalクラス」について解説していきます。
Optionalクラスとは
簡単に説明すると、Optionalクラスはnullかどうかの判定を自動で行ってくれるクラスです。
プログラマーの方なら一度は経験しているであろうnullチェックの忘れによるバグを未然に防ぐ目的で使用します。
またnullの場合に通例として行う処理も、このOptionalクラスを使えば簡単に記述することが出来ます。
Nullチェックの落とし穴
ざっと解説してみましたが、恐らく文章だけでは何のことだかわからないと思いますので、実際にコードを使って見てみましょう。
package sample; import java.util.Random; public class OptionalSample { static OptionalSample getSample() { OptionalSample sample = null; if (new Random().nextBoolean()) { sample = new OptionalSample(); } return sample; } String hello() { return "Hello, World."; } public static void main(String[] args) { OptionalSample sample = getSample(); System.out.println(sample.hello()); } }
このコードでは”getSample”で”OptionalSample”を取得し、”Hello”というメソッドを呼び出すプログラムです。
但しgetSampleメソッド内のif文でランダム指定してあるので、インスタンスが生成されるかどうかは運任せとなっているため、もし論理値がtrueでないなら即座に”NullPointerException”が発生し、プログラムが実行されません。
通常であればこのプログラムにはnullチェックを挟むはずですが、作り手がnullが発生する可能性に気づいていなければ、恐らくnullチェックを省略するでしょう。
このようにプログラマーの見落としがバグとなることもしばしばあります。
Optinalクラスを使ってみる
それでは今度はOptinalクラスを使ってみましょう。
メソッドでOptinalクラスを使用する場合には以下のように記述します。
public static Optional ofNullable(value)
ofNullableメソッドの引数にはnullの可能性があるオブジェクト名を指定します。
それでは早速先ほどのコードを、このOptinalクラス用に書き換えてみましょう。
package sample; import java.util.Optional; import java.util.Random; public class OptionalSample { static Optional<OptionalSample> getSample() { OptionalSample sample = null; if (new Random().nextBoolean()) { sample = new OptionalSample(); } return Optional.ofNullable(sample); } String hello() { return "Hello, World."; } public static void main(String[] args) { Optional<OptionalSample> opt = getSample(); if (opt.isPresent()) { OptionalSample sample = opt.get(); System.out.println(sample.hello()); } } }
“static Optional<OptionalSample> getSample()”の部分を見てください。
Optionalのダイヤモンド演算子(<>で囲まれた部分)にはラッピングしたいクラス名を入れるようにします。
またOptionalの値を取り出す場合にはOptional.get()を使用します。
しかしそのままgetを使うと、やはりランダムでエラーを吐き出しますので、この場合にはif文でnullチェックを行います。
チェックには”isPresent”を使用します。isPresentは値がある場合にtrueを返します。
これで一連の流れが整いましたので、nullがあった場合にもエラーが図れることはなくなりましたが、まだこれでは不十分で便利さが分からないと思います。
そこで次はもう少しスマートで便利な方法をご紹介します。
ifPresentOrElseを使う
先ほどのコードでは”isPresent”を使いましたが、値が無いときの処理を同時に記述するには”ifPresentOrElse”を使用します。
“ifPresentOrElse”は”isPresent”の派生メソッドで、第二引数を指定することによって値の無い場合の処理を記述することが出来ます。
ifPresentOrElseの記述ルールは以下の通りです。
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
先ほどのコードで説明するなら以下のように記述を変更します。
public static void main(String[] args) { Optional<OptionalSample> opt = getSample(); if (opt.isPresent()) { OptionalSample sample = opt.get(); System.out.println(sample.hello()); } Optional<OptionalSample> opt = getSample(); opt.ifPresentOrElse(v -> System.out.println(v.hello()), () -> System.out.println("nullです")); }
こうすることで、if文を使用することなくnullの場合の処理も記述できます。
デフォルトを指定するならorElseを使う
同じようにデフォルトで何かの処理をさせる場合には”orElse”を使用します。
“orElse”はif文でいうところのelseに該当します。
先ほどのコードを更にorElseに置き換えてみましょう。
Optional opt = getSample(); OptionalSample sample = opt.orElse(new OptionalSample()); System.out.println(sample.hello());
これで、nullの場合も同じ処理をさせることが出来るようになりました。
if文を書くことなくif文記述時と同じ処理を実行できますので、ここまでくるとOptionalの便利さが実感できたと思います。
複雑なコードになってくると忘れがちなnullチェックですが、このようにOptionalを使うことで煩わしさから解放されると同時にエラーを未然に防ぐことも出来ます。
まとめ
今回は簡単ではありましたがOptionalについて解説してみました。
Java8から導入されたクラスですが大変便利な機能となっていますので、確実にマスターして使いこなせるように何度も繰り返し学習するようにしましょう。
特にコードが複雑になることが想定される際には効果を発揮するはずです。