koetaihito
@koetaihito

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

JavaのorElseGet()メソッドなどの引数がSupplierである理由がわかりません

Q&A

解決したいこと

そもそもSupplierの存在意義がよくわかりません。必要な場合だけインスタンスを生成するくらいしか用途がないように思えます。

そのうえで、Optional.orElseGet()Optional.orElseThrow()の引数がSupplierである理由がわかりません。直接インスタンスを渡す実装になっていないのはなぜでしょうか。

いくら調べてもどこにも理由が説明されていませんでした。回答はできれば根拠の伴う形でお願い致します。

0

3Answer

今ひとつ質問の意図が分かりかねますが,↓の違いのことについてという意味で良いのでしょうか?
であれば究極的にはコンパイラの都合というしかない気もしますが…

Optional.empty().orElse(new Hoge());

Optional.empty().orElseGet(()->new Hoge());

Supplier自体は存在意義も何もただのインターフェースなので,関数として使えりゃ何でも同じです.

1Like

Comments

  1. @koetaihito

    Questioner

    なぜこれらのAPIが直接インスタンスを渡すような設計になっていないか、という意図で質問しました。
    分かりづらく申し訳ないです。
    直接インスタンスを渡せばいいのに、わざわざSupplierにしているため、ラムダ式の分、余計なインスタンスを生成するのが意味不明だということです。

  2. @koetaihito

    Questioner

    加えて、Supplierを使う場面があるのかという話です。

  3. ここあたり読んでいただきたいのですが,orElseに渡した引数は即時評価されます.
    これはJavaランタイムが引数に渡された値を確定させておかなければならないためどうしようもありません.

    なので負荷がかかるインスタンス生成なんかを呼ぶとえらいことになるということです.
    ラムダ式の分余計にオブジェクトが増えるというのが全くの誤解で,遅延評価の助けを借りて無駄にインスタンスを生成しないためのorElseGetです.

    先述しましたがSupplier自体の名前はどうでも良くて関数として使えれば何でも同じです.

orElseは常に返す値を生成する。
orElseGetは必要になったら値を生成する。
つまりorElseGetは遅延評価をしている。

必要な場合だけインスタンスを生成するくらいしか用途がない

遅延評価のメリットはいくつかあるけど、orElseGetであれば、まさに上記のことがメリットになる。
インスタンスの生成に大きなコスト(リソースだの時間だの通信だの)がかかる場合、真に必要な時にしかインスタンスの生成をしないので、処理を最適化できる。

インスタンスの生成コストが無視できるほど小さくorElseで十分なのであれば、orElseGetは使う必要がない。
orElseGetは必要なタイミングで使えばいい。

Supplierの存在意義は、関数オブジェクトや遅延評価等のメリットを調べてください。
関数オブジェクトは必須の存在ではありません(Java7まではなかったわけですし)が、あるとすごく便利なものです。

1Like

質問に回答してくださったお二方、ありがとうございます。
ではOptionalが空だった場合にインスタンスを生成するコードを書けばラムダ式のインスタンスを生成せずに済むので効率的ですよね?
なぜそうしないのかがわかりません。
また、当方は関数については有用だと考えていますが、ConsumerやPredicateに比べてSupplierの用途が不明確だと述べています。
よろしくお願いいたします。

0Like

Comments

  1. そもそもOptionalの存在意義は無いかもしれない戻り値をメソッドユーザーに明示することです.
    この辺をご覧いただければと思います.

    つまり何が言いたいのかと言うと

    ではOptionalが空だった場合にインスタンスを生成するコードを書けば

    という判断をメソッドの利用者に委ねることができます.
    nullのままでいい場合はインスタンスを生成する必要すらないですから…

    あと何度も言ってますがSupplierは引数を持たずT型の戻り値を返す関数という以上の意味はないので名前とか存在意義とかはどうでもいいんです.これはConsumerもPredicateも同じです.なんなら既存のstatic関数を流用できます.
    これは関数インターフェースすべてにいえますが,Comparator.compareでやってたような(つまり明示的にComparatorを実装する記述をする必要があった)ことがいちいち関数の名前をつける必要がなくなったとだけ覚えてください.

  2. ではOptionalが空だった場合にインスタンスを生成するコードを書けばラムダ式のインスタンスを生成せずに済む

    つまり以下のようなコードを書けば、ラムダ式の生成コストなくせるんじゃん!って言ってる?

    Optional<String> optional = Optional.empty();
    
    Hoge hoge = null;
    if (optional .isPresent()) {
        hoge = optional.get();
    } else {
        hoge = new Hoge();
    }
    

    もしこれのことを言ってるんだとしたら、すごく反対する。
    コードの見通しが悪すぎる。
    逆に聞くけどラムダのインスタンス生成ってそんなに重いものなの?
    私の認識だとラムダの生成コストは気にするレベルではなく、コードがシンプルできれいであることのほうがずっと重要だと思ってる。

    当方は関数については有用だと考えていますが、ConsumerやPredicateに比べてSupplierの用途が不明確だと述べています。

    むしろSupplierだけ不明瞭だと認識していることがよくわからない。
    引数と返却の個数が違うだけで、ほぼ一緒じゃん。必要な場面がちょっとずつ違うだけで、意味は一緒だよ。

Your answer might help someone💌