グアバのオプションクラスのポイントは何ですか


89

私は最近これについて読んだり、このクラスを使用している人々を見たりしましたが、ほとんどすべての場合、使用nullすることも同様にうまくいきました。誰かOptionalnullできなかった、またははるかにクリーンな方法で達成できる具体的な例を誰かが提供できますか?私が考えることができる唯一のことMapsは、nullキーを受け入れないでそれを使用することですが、それでもヌルの値の「マッピング」側で行うことができます。誰かがもっと説得力のある議論を私に提供できますか?ありがとうございました。


12
ランダムな怒り:人々が「パターン」を使いすぎたときにそれを嫌い、存在しない理論的な利点のためにコードをとても醜く見せます...
RAY

Java8の時点では、JDKのクラスほど強力ではないため、このGuavaクラスを使用しなくなりました。stackoverflow.com/a/10756992/82609を
Sebastien Lorber 14

回答:


155

グアバのチームメンバーはこちら。

おそらく単一の最大の欠点はnull、特定のコンテキストでそれが何を意味するのかが明らかではないことです。これには、説明的な名前がありません。それがnull「このパラメータに値がない」という意味であることが常に明らかであるとは限りません。つまり、戻り値として、「エラー」または「成功」(!!)を意味することもあれば、単に「正しい答えは何もない」こともあります。Optional多くの場合、変数をNULL可能にするときに実際に意味する概念ですが、常にそうであるとは限りません。そうでない場合は、Optional実際の意味を明らかにするために、命名スキームが似ているが異なる命名規則を使用して独自のクラスを作成することをお勧めします。

しかし、私が言う最大の利点はOptional読みやすさではありません。その利点は、ばかであるということです。プログラムをコンパイルする必要がある場合は、存在しないケースについて積極的に考える必要がOptionalあります。それは、を積極的にアンラップして対処する必要があるためです。Nullを使用すると、物事を簡単に忘れることが非常に簡単になります。FindBugsは役立ちますが、この問題にはほとんど対応していないと思います。これは、「存在」する場合としない場合がある値を返す場合に特に関係があります。あなた(およびその他)のことを忘れることがはるかに可能性がありますother.method(a, b)返すことができるnullあなたがそれを忘れるためにそうしているよりも、値をaすることができnull、あなたが実装しようとしているときother.method。戻るOptional 呼び出し側はオブジェクト自体をアンラップする必要があるため、その場合を忘れることはできません。

これらの理由により、Optionalメソッドの戻り値の型として使用することをお勧めしますが、必ずしもメソッドの引数では使用しないでください。

(ちなみに、これはここでの議論から完全に不満です。)


3
すばらしい説明は+1です。これがインスピレーションであるかどうかはわかりませんが、SML、OCaml、F#のオプションタイプへのポインタを追加しますが、これらには同じセマンティクスが多数あります。
アダムミハルシン2012年

2
直接関わった人からの回答を得るのはいつも素晴らしい。そのためだけに+1しました。すばらしい答えを得るには、さらに+1します。(しかし、私はできません。)見慣れないメソッドのコンシューマーに「何も」が返されないことを認めさせる努力を強いるために、それを戻り値として持つことのポイントは、説得力のある理由の1つだと思います。私はそれがどのように過度に使用されている(または乱用されている)かは好きではありません。たとえば、マップにOptionalsを値として入力するのを見ると、本当に不安になります。存在しない/マッピングされていないキーに対してnullを再マップするマップは、確立されたパラダイムです...より複雑にする必要はありません...
RAY

9
それは十分に確立さだとMapリターンnullキーがマップされていないが、あなたがしなければというリコールであればmap.put(key, null)、その後、map.containsKey(key)戻りますtrueが、map.get(key)戻りますnullOptional「明示的にnullにマップされた」ケースと「マップに存在しない」ケースの違いを明確にするのに便利です。私はそれOptionalが悪用される可能性があることを認めますが、あなたが述べた事件が虐待であるとはまだ確信していません。
Louis Wasserman 2012年

8
時代遅れの類推を使用するには、「電話帳」と呼ばれるこれらの巨大なものがありました:-)私が誰かの番号を調べるように頼んだら「その人には番号がない」と言ったら、私は「あなたは何をしますか」つまり、リストにない番号でそこにいるのか、それともそれらのエントリがまったく見つからなかったのですか?」これら2つの可能な応答は、それぞれOptional.absent()とnullにうまく対応しています。Optional.absent()は決定的な「正の負」です。
Kevin Bourrillion、2012年

3
@RAY:ある意味でOptional<T> 、その「見つかったが無効な」値です。より正確にOptional<T>は、追加の「見つかったが有効ではない」値で任意の型を装飾する方法Tです。2つの既存の型を組み合わせて新しい型を作成します。クラスが100ある場合、クラスごとに「見つかりましたが、有効ではない」値を個別に作成する必要がありますがOptional<T>、すべてのクラスで簡単に機能します。
Daniel Pryden 2012年

9

それは本当にMaybeHaskell のモナドパターンに似ています。

次のウィキペディアモナド(関数型プログラミング)をお読みください。

また 、モナドとして使用されるグアバのオプションについては、Kerflynのブログで「オプションからモナドへのグアバへ」を参照してください


編集: Java8には、のようなモナド演算子を持つ組み込みのOptionalがありflatMapます。これは物議を醸す問題でしたが、ついに実装されました。

http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.htmlを参照してください

public Optional<String> tryFindSimilar(String s)  //...

Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

flatMapオペレータは、簡単にチェーンコールそのすべての戻りオプションの結果にモナドの操作、および許可を許可することが不可欠です。

考えてみてください。map演算子を5回使用した場合Optional<Optional<Optional<Optional<Optional<String>>>>>、結果flatMapはになりますが、使用するとOptional<String>

Java8以降は、それほど強力ではないGuavaのOptionalを使用したくありません。


6

これを使用する理由の1つは、ヌルを非常に意味のあるものにすることです。多くのことを意味する可能性のあるnullを返す代わりに(エラー、失敗、空など)、nullに「名前」を付けることができます。この例を見てください:

基本的なPOJOを定義しましょう:

class PersonDetails {

String person;
String comments;

public PersonDetails(String person, String comments) {
    this.person = person;
    this.comments = comments;
}

public String getPerson() {
    return person;
}


public String getComments() {
    return comments;
}

}

次に、この単純なPOJOを使用します。

public Optional<PersonDetails> getPersonDetailstWithOptional () {

  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,
  lets make the return value more meaningful*/


    if (details == null) {
      //return an absent here, caller can check for absent to signify details are not present
        return Optional.absent();
    } else {
      //else return the details wrapped in a guava 'optional'
        return Optional.of(details);   
    }
}

ここで、nullの使用を避け、オプションでチェックを実行して、意味のあるものにします。

public void checkUsingOptional () {

    Optional<PersonDetails> details = getPersonDetailstWithOptional();

    /*below condition checks if persons details are present (notice we dont check if person details are null,
    we use something more meaningful. Guava optional forces this with the implementation)*/
    if (details.isPresent()) {

      PersonDetails details = details.get();

        // proceed with further processing
        logger.info(details);

    } else {
        // do nothing
        logger.info("object was null"); 
    }

    assertFalse(details.isPresent());
}

したがって、最終的にはnullを意味のあるものにし、あいまいさを減らす方法です。


4

Optionalの最も重要な利点は、関数の実装者と呼び出し元の間のコントラクトに詳細が追加されることです。このため、パラメーターと戻り値の型の両方に役立ちます。

Optional可能性のあるnullオブジェクトに対して常に持つ規則を作成する場合は、次のような場合にさらに明確化を加えます。

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    ここでの契約は明らかに結果が返されない可能性があることを指定するだけでなく、それはで動作することを示しているfromto不在として。

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    コントラクトはfromがオプションであることを指定しているため、存在しない値はstart from 2のような特別な意味を持つ可能性がtoあります。パラメーターのnull値が例外をスローすると予想できます。

したがって、Optionalを使用することの良い点は、コントラクトが(@NotNull注釈と同様に)説明的であると同時に正式なものになったことです。これは.get()、に対処するコードを記述する必要があるためですOptional


空のリストがよりクリーンになるのに、なぜOptional <List>を使用するのですか?
レイ2013年

私は帰りに間違った例を選びました。コレクションを使用すると、null値ではなく常に空のコレクションを返すように規則を設定できます。この規則を使用する場合、コレクションにオプションは必要ありません。Optionalは、ゼロまたは1つの要素を持つコレクションとして認識される可能性があるため、他のコレクションの周囲に配置する必要はありません。
レイザーコスタン2013年

2
コンテキストによっては、0アイテムのリストと存在しないリストの間に意味のある違いがある場合があります。
プラズマ147 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.