私は最近このことを読んで、このクラスを使用している人を見ましたが、ほとんどすべての場合、null
を使用しても同様に機能します-より直感的でないとしても。誰かがOptional
がnull
が達成できなかった、またははるかにきれいな方法で達成する具体的な例を提供できますか?私が考えることができる唯一のことは、Maps
キーを受け入れないnull
でそれを使用することですが、それでもnullの値のサイド「マッピング」で行うことができます。誰も私にもっと説得力のある議論を提供できますか?ありがとうございました。
グアバチームのメンバーはこちら。
おそらくnull
の最大の欠点は、特定のコンテキストでそれが何を意味するのかが明確でないことです。これには説明的な名前がありません。 null
が「このパラメーターに値がない」ことを意味することは必ずしも明らかではありません-戻り値として、「エラー」、「成功」(!!)、または単に「正しい」答えは何もない」。 Optional
は、変数をNULL可能にするときに実際に意味する概念ですが、必ずしもそうとは限りません。そうでない場合、実際の意味を明確にするために、Optional
に似た独自のクラスを作成することをお勧めしますが、命名規則は異なります。
しかし、Optional
の最大の利点は読みやすさではありません。その利点は、その馬鹿な証拠です。 Optional
を積極的にアンラップし、そのケースに対処する必要があるため、プログラムをコンパイルしたい場合は、不在のケースについて積極的に考える必要があります。 Nullを使用すると、単純に物事を簡単に忘れることができます。FindBugsは役立ちますが、問題をほぼ同様に解決できるとは思いません。これは、「存在する」場合とそうでない場合がある値を返す場合に特に関連します。あなた(および他の人)は、[other.method(a, b)
がnull
値を返すことを忘れる可能性がはるかに高く、a
がnull
であることを忘れる可能性が高いother.method
を実装しているとき。 Optional
を返すと、呼び出し側はそのケースを忘れることができません。オブジェクトを自分でアンラップする必要があるためです。
これらの理由から、メソッドの戻り値の型としてOptional
を使用することをお勧めしますが、必ずしもメソッドの引数で使用する必要はありません。
(これは、議論から ここ です。)
Haskellの Maybe
Monadパターンのように見えます。
次のウィキペディアを読む必要があります Monad(関数型プログラミング) :
そして、 グアバのあるモナドへのオプショナルからKerflynのブログ を読んでください。モナドとして使用されるグアバのオプショナルについて議論しています:
編集:Java8には、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は使用しません。
これを使用する理由の1つは、nullを非常に意味のあるものにすることです。多くのこと(エラー、失敗、空など)を意味する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());
}
したがって、最終的にはヌルを意味のあるものにし、曖昧さを軽減する方法です。
Optionalの最も重要な利点は、関数の実装者と呼び出し元の間のコントラクトに詳細を追加することです。このため、パラメーターと戻り値のタイプの両方に役立ちます。
可能性のあるnullオブジェクトに対して常にOptional
を使用する規則を作成する場合、次のようなケースにさらに明確化を追加します。
Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)
ここでの契約は、結果が返されない可能性があることを明確に指定していますが、from
およびto
が存在しない場合でも機能することを示しています。
Optional<Integer> maxPrime(Optional<Integer> from, Integer to)
コントラクトではfromがオプションであるため、absentの値はstart from 2のような特別な意味を持つ場合があります。to
パラメーターのnull値が例外をスローすることが予想されます。
したがって、Optionalを使用する良い点は、契約が記述的(_@NotNull
_アノテーションと同様)になっただけでなく、Optional
に対処するためにコード.get()
を作成する必要があるため、正式になったことです。