2020の20日目の記事です。Qiitaとダブルポストです。2014年にJava8がリリースされ、そこからOptionalの機能が導入されました。Java15(2020年9月リリース)が最新です。Java8がリリースされてから、11がでるまでの間に始まったプロジェクトでは、まずJava8が使われているでしょう。AWSではJava8のサポートをかなりのばしているので、まだまだ使う機会がありそうです。Java8のOptionalは決して使いやすいとはいえないですが、それでもマッチしたケースではそれなり有効です。ケース別にどういった使い方をすればいいかをまとめてみました。英語ではOptionalを使ってはいけないケースをまとめた記事も結構あります。そのうちのいくつかをピックアップしてみました。書いたあとから、公式で結構良いブログがあるのを見つけました。これはJava11までを考慮した形で、きれいにまとまっています。原則使わないようにしましょう。Optional#get()は値が存在しないときは例外スローされます。checkしないで参照するのと同じことになります。(NullPointerExceptionのかわりに、NoSuchElementExceptionがスローされます。)なんのチェックもしないでOptional#get()を使った場合、最近のIDEやSonarLintなどの静的解析ツールでは、警告がでてきます。Optionalからの値の取り出し方として良くないとして、すでに知られているといえます。Optionalを使い始めのときにやりがちなので、注意が必要です。Optionalを使うためには、Optionalで包んだ値の取り出し方(使い方)を知っていることが重要です。関数型のパラダイムを最初からとりいれている言語であれば、取り出し方自体がJava8に比べて豊富で、IDEでだいたい然るべきメソッドにたどり着きやすいと思います。Java8では選択肢が少ないとの、高階関数のAPIがあまり使い勝手が良くないので、取り出し方を先に意識しないと、「Optional使ってみたけど、なんか読みづらいし、書きにくい」、となりがちです。各メソッドの詳細はjavadocを参照してください。以下のメソッドをつかって取り出します。userOpt.orElseThrow(IllegalStateException::new)なんらかの変換や絞り込みが必要な場合は、以下のメソッドを先に使ってから、上記にあげたメソッドで値を取り出します。ように、Optionalが2重になるような変換がある場合は、flatMapを使います。今回はこれはとりあげません。上記を組み合わせて、必要な値の取り出しや処理します。findByIdなど、検索結果が最大1件しかない場合はOptionalで受け取ることができます。いった場合、entityのままで扱いたいケースが多いです。exist"));}包んだ値が持っているプロパティを使うentityがもっている特定のプロパティだけが必要なケースがあります。いう場合は、Optional#mapを使います。user.map(User::getStatus).map(UserStatus::getValue).orElse(0);包んだ値をもとになんらかの変換して使うentitをそのままでなく、画面表示用にいろんな加工が必要な場合などは、別のオブジェクトに変換することがあります。methodを用意しておくと、Optional#mapをうまく使えます。methodが用意されています。ofNullablenullのときは空のOptionalを、そうでないときはその値のOptionalを返します。実際のコーディングではこれを使うことが多いです。Optionalで取り扱いたいが、ライブラリではそうなっていないときなどに、使います。JPAと違って、ebeanというORMでは、主キーでの検索結果はOptional型になっていません。同じ様にOptionalで扱いたければ、下記のようにします。Optional.ofNullable(User.find.byId(1L));empty空のOptionalを返すメソッドです。あるのは、例外がおきたときなど、明示的に空のOptionalを返せるときに使います。}ofnon-nullな値をOptionalにするときに使います。nullでないことがわかっていて、かつOptionalを使った方がいいという、実用的なケースがあまりなさそうです。返り値がOptionalのメソッドのテストコードなどでは、使いみちがあるかもしれません。存在しないときは初期値を使えるorElseかorElseGetを使います。初期値の生成のコストが大きいときは、orElseGetを使います。user.map(User::getId).orElse(1L);値がなにも入っていないインスタンスを初期値として渡す場合はorElseGetが使えます。nullを返すよりも空のインスタンスの方が、なにかと取り扱いがいいです。upsert処理用のインスタンスを作るときなどに使えます。user.orElseGet(User::new);存在しないときは例外スローできるorElseThrowを使います。存在しないときの処理を、例外をキャッチする別の箇所でやれる場合などに使えます。APIで、id指定のエンドポイントの実装などに使えます。ResponseEntity.ok(user);}存在しないときはなにも処理しないifPresentを使います。存在するときにだけになにか処理するときに使えます。更新系の処理で、正しいidが指定されたときだけ実行するというときなどに使えます。userRepository.save(x);});存在しないときは別の処理をするJava8では、isPresentとif文を使うことになります。この場合は、isPresentのチェック後に、Optional#get()で値を取り出します。存在しない場合はログ出力するときなどです。存在しないときの処理}Java8でこのケースになった場合は、Optionalを使い続けるメリットがあまりないです。orElseなどで、値を取り出し、そこで値があるかないかを別の形でチェックするのを検討してみましょう。存在するケース}Java9からifPresentOrElseが追加されていて、存在しないケースも関数でかけるようになりました。}):存在したとき、なんらかの条件で絞り込みたいfilterを使います。DBからの取得する段階では絞り込みができないときなどに使います。.orElseThrow(IllegalStateException::new);Optionalは使わない方がいいケースStringや、intなどのプリミティブ型をOptionalで包みたいStringの場合は、nullを極力使わず、値がないことは空文字で表現すればだいたいのことはできます。...}int,longなどは、OptionalInt、OptionalLongなどの専用のOptional型は用意されています。APIを使った際に使うことが想定されているようです。checkすればいいです。リストなどのコレクション型をOptionalで包みたい基本的には不要です。nullを使わず、空のコレクションかどうかで、値の有無を判定しましょう。返り値がコレクション型のメソッドを作る場合、nullではなく空のコレクションを返却すればいいです。すれば、Optionalでラップする機会はないです。大概のライブラリはそのような使用になっています。...}メソッドの引数にOptionalを使いたいnullを引数に渡すことは一般的にはよくないことと知られています。これもそれの延長ということです。Optionalを渡すと、なかで存在するかどうかのチェックをすることになります。メソッド内でやるよりも、呼び出し側でOptionalをはずした方が、メソッドも使いやすく、読みやすくなるようです。user.orElseGet(User::new));成功(正常)か失敗(異常)かどうかを返り値で判定したい成功のときは値があるOptional、そうでないときは空のOptionalを返す、として、呼び出し側で、成功か失敗に応じて処理を分けたい、というような使い方です。...}これはisPresentを使うケースにつながるので、単純なケースでない限りはやらない方が良さそうです。Either型がある言語では、それを使えばいいのですが、ない場合はそれに近いものを用意せざるを得ないです。結果用のオブジェクトをつくって、その中に成功かどうかのフラグや、返却したいものをつめるといいです。...}まとめ参考リンクhttps://qiita.com/nowokay/items/2858699bc1cd89222cd8https://qiita.com/BlueRayi/items/ef46496ef2ef36b9cbb7https://qiita.com/yamadamn/items/2dd26a014791b9557199https://qiita.com/nowokay/items/1ce24079f4daafc73b4ahttps://dzone.com/articles/java-8-optional-usage-and-best-practiceshttp://dolszewski.com/java/java-8-optional-use-cases/https://www.baeldung.com/java-optionalhttps://www.baeldung.com/java-optional-returnhttps://community.oracle.com/tech/developers/discussion/4418055/optionals-patterns-and-good-practiceshttps://www.dariawan.com/tutorials/java/using-java-optional-correctly/https://javadevcentral.com/a-complete-guide-to-java-optionalhttps://ducmanhphan.github.io/2019-12-06-Best-practice-for-Optional-in-Java/https://tech401.com/2017/12/01/2017/2017-11-30-java-optional-good-and-bad/https://www.baeldung.com/java-constructors-vs-static-factory-methodshttp://sumikitch.com/blog/2019/02/17/java-static-factory-method/https://www.baeldung.com/java-9-optionalhttps://qiita.com/tasogarei/items/f289d125660af6fe5ba6https://stackoverflow.com/questions/4535112/is-null-arguments-a-bad-practicehttps://qiita.com/suzuki-hoge/items/4f223022626b5b7d601chttps://blogs.oracle.com/otnjp/recipes-for-using-the-optional-class-as-its-meant-to-be-used-janslenderだいたいJavaをやっていますバッジを贈って著者を応援しようバッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。Proよくある質問LinksX(Twitter)GitHubメディアキットLegal利用規約プライバシーポリシ。