JavaのOptionalを試してみる

f:id:ts0818:20190505202403j:plain

Java でクラスのフィールドのNULLチェックとかして、というか、Java 8 で導入されたStreamとラムダ式の絡みで、NullPointerException を回避したいじゃないっすか...どうもボクです。

Java 8 で導入された、Optionalっちゅうものを使ってイケるらしいと。

 

そして、ぜんぜん関係ないけど、

qiita.com

⇧  衝撃... 

magazine.gow.asia

なぜ「うるう日」が「逆プロポーズの日」になったのでしょうか?

1288年、スコットランドのマーガレット女王は、
「未婚の女性はうるう年ごとに、好きな男性に対してプロポーズすることができる。男性がプロポーズを拒むには、罰金を払うか、絹のドレスを与えなければならない」という法律を制定しました。
これではさすがに、うるう年の一年の間ずっと、プロポーズを拒めないことになりますので反発も多く、その後、うるう日のみに改訂されました。
同じような法律はフランスにもあり、15世紀にはイタリアでも慣習になっていました。

今年はうるう年!2月29日は「逆プロポーズを断ると罰金の日」 | yummy!

⇧  4年に一度か...オリンピックとおんなじか~...でも、願わくば男性版の法律も作って欲しいところです

 

というわけで、Optional ってどう使うの?ってな部分を調査していきますか~。レッツトライ~。

 

Optionalとは?

まずは、Javadocの説明を見てみますか。

docs.oracle.com

クラスOptional<T>



  • public final class Optional<T>
    extends Object
    null以外の値が含まれている場合も含まれていない場合もあるコンテナ・オブジェクトです。値が存在する場合、isPresent()trueを返し、get()は値を返します。

    含まれる値の有無に応じて追加メソッドが提供されます。たとえば、orElse() (値が存在しない場合にデフォルト値を返す)、ifPresent() (値が存在する場合にコードのブロックを実行する)など。

    これは値ベースのクラスで、Optionalインスタンスに対して、ID依存操作(参照等価性(==)、IDハッシュ・コード、同期など)を使用すると、予期できない結果になる可能性があり、避けてください。

    導入されたバージョン:
    1.8

Optional (Java Platform SE 8)

⇧  サッパリですな...コンテナ・オブジェクトって何のこっちゃ?

Wikipediaさんによりますと、

コンピュータプログラミングにおいて、コンテナとはオブジェクトの集まりを表現するデータ構造抽象データ型またはクラスの総称である。コレクションとも言う。コンテナには複数の種類があり、それぞれ独自の方法でオブジェクトを組織的に格納する。

よく知られたものには、

などがある。

コンテナ (データ型) - Wikipedia

⇧  ってなってるけど、こういう認識で良いってことですかね?

 

www.kab-studio.biz

何かを入れて運ぶクラス。 
いくつかの意味がある。 
  
コレクションクラス」のことを指す場合。 
クラスの中に各クラスを「格納」できるため、ArrayListクラス等のコレクションクラスを「コンテナクラス」と呼ぶ場合がある。 
  
そのものずばり、Containerクラスというものも存在する。 
ContainerクラスAWTクラスのひとつで、ウィンドウを表示する場合に、ボタン等を入れる「枠」となるクラスである。ウィンドウを表示するWindowクラスもこのContainerクラスサブクラスである。 
  
Webアプリケーションを実するためのクラスも「コンテナクラス」と呼ばれる。 
サーブレットを実するクラスを「サーブレットコンテナ」、JSPを実するクラスを「JSPコンテナ」と言う。また、それらを総称して、アプリケーションサーバーそのものを「サーブレット/JSPコンテナ」「Webコンテナ」もしくは単に「コンテナ」と言うこともある。 
  
このように、様々な意味を持つ単語のため、どの意味かは文脈から読み取る必要があるため注意。

コンテナクラスとは : JavaA2Z

⇧  上記サイト様によりますと、文脈から読み取れとありますね...javadoc の説明だとまったく読み取れんけど...まぁ、「Optional<T>」ってなってるから、T にはどんなものでも入るって認識で大丈夫なんでしょうかね... 

 

Optional の使い方については、

irof.hateblo.jpqiita.com

qiita.com

⇧  上記サイト様が詳しいです。 

Java界隈の著名人であられる、きしださんも、

nowokay.hatenablog.com

⇧  かなり、早い時期に Optional  について言及されてますね。2013年って...あっしは、まだパソコンに触れたことがない時代ですね...

んで、きしださんのブログで、Optional のモナドについての議論が紹介されてました。海外の勇気ある人が、Javaの中の人にリクエストしたことにより、「map」「flatMap」のメソッドが実装されたそうな...

 

Optional はメソッドの戻り値として使うらしい

らしいっす。

なんか、自分でクラスとか作成してたら、そのクラスのメンバーメソッドなんかで戻り値が、Optional<T> なものを用意しておいてあげないといけないらしい。

アンチパターンとしては、

dzone.com

⇧  上記サイト様で紹介されてるのですが、少なくとも、

  1. Optional Types in Object Fields
  2. Collections of Optionals
  3. Optional as a Method Argument
  4. Trying to Serialize Optionals

の4つの使用法はNGらしいっす。

4つ目については、

In case you really, really need to serialize Optional, you have to consider using different libraries, like Guava Optional or Vivr Optional.

Optional Anti-Patterns - DZone Java

⇧  「どうしてもシリアライズなOptional を実装したいなら、外部APIGoogle GuavaやVivrのOptional を使え」って言ってますね、っていうか「Vivr」ってのが何なのか分からん...Vavr(旧:Javalang) ってのは存在するらしいけど。

というか、コレクションで使ったらアカンって...Optionalの流儀がよく分からんですな...

 

nowokay.hatenablog.com

  1. Do not declare any instance variable of type Optional.
  2. Use null to indicate optional data within the private scope of a class.
  3. Use Optional for getters that access the optional field.
  4. Do not use Optional in setters or constructors.
  5. Use Optional as a return type for any other business logic methods that have an optional result.

Stephen Colebourne's blog: Java SE 8 Optional, a pragmatic approach

⇧  きしださんが、Optional の使いどころを紹介してくれてました。

こんな感じですね。

  1. インスタンスフィールドにOptionalは使わない
  2. プライベートスコープではnullを使う
  3. getterにはOptionalを使う
  4. setterやコンストラクタではOptionalを使わない
  5. メソッドの戻り値にはOptionalを使う

ただ、このとおりにやるとvoid setSome(Some some)/Optional getSome()となるのでsetter/getterの型が違ってしまいます。このような場合に対応していないフレームワークも多いと思うので、単純ではなさそう。

OptionalがSerializableではない話と使い方まとめ - きしだのHatena

Lombok とか使ってる場合、Optional ってどうすれば良いのやらですね... 

qiita.com

⇧  上記サイト様によりますと、やはり相性が良くないみたいですね...

 

Optional を使ってみる

んで、やりたいことは、クラスのフィールドが入れ子のオブジェクトになってるようなパターンのnull チェックですよね~、っていうことで、

stackoverflow.com

You can use Optional.flatMap here

employee.getHuman()
        .flatMap(Human::getMale)
        .flatMap(Male::getAge)
        .ifPresent(age -> System.out.println("I discovered the variable finally " + age);

Java 8 Optional - how to handle nested Object structures - Stack Overflow

 ⇧  上記サイト様で、「Optional.flatMap」使ったらいけますぜ、と。

ただ、これ、質問者の方のクラスの作りが、インスタンスフィールドにOptional 付けたり、メソッドの引数にOptional 付けたり、アンチパターンを使いまくってる...

 

www.oracle.com

⇧  なんか、Oracleさんも普通に、アンチパターンやってますね...

改善が必要とは言ってるし、Google Guvnaでも似たようなことやってるって言ってる風なんだけど、Googleもおんなじような問題を抱えてるんじゃない?的なことを暗に言わんとしてるのか...相変わらず、Oracle適当ですな...

最早、正解が分からない... 

2014年3月の内容なので今は改善されてるのか分からんけども、少なくともそういう情報は出てこないけども...調べ方が悪いとは思うけど...

 

2019/5/18(土)に、

www.java-users.jp

⇧  JJUG(Japan Java User Group)のイベントがあるので、行った時に聞いてみますかね...

 

差し当たっては、アンチパターンと言われてるもので実装するしかなさそうですね...

んで、実装してみて、くそハマった...

qiita.com

⇧ 上記サイト様と同じ状況かな~、と思ったんだけども、Optional.flatMapの使い方を普通に間違ってました...。

 

Eclipseを起動し、適当なJavaプロジェクト、クラスを作成で。

今回は、

github.com

⇧  ちょっとクラスが多くなったので、ソースコードGitHub にアップしました。

一応、プロジェクトの構成は、下記画像で。

f:id:ts0818:20190506174936p:plain

まぁ、何ていうか、Optional 使い方が難しい...っていうか結局、良く分からん...

flatMap とかも良く分からんし...

Streamに関してのflatMapについては、

qiita.com

⇧  上記サイト様が詳しいです。

Stream と Optional の flatMap の比較については、

ky-yk-d.hatenablog.com

⇧  上記サイト様が詳しいです。

 

きしださんも仰てましたが、「モナド」について

qiita.com

⇧  上記サイト様が説明してくれていました。

 

覚えなきゃならんことが多すぎて...いっぱいいっぱいです...

今回はこのへんで。