web-dev-qa-db-ja.com

nullを返す可能性のあるすべてのメソッドにJava8 / Guava Optionalを使用する必要がありますか?

オプションは、null許容オブジェクトを表すために使用されます。このクラスの用途には、

  1. メソッドの戻り値の型として、nullを返す代わりに
    値が利用できなかったことを示す
  2. 「不明」(たとえば、マップに存在しない)と「値を持たないことがわかっている」(マップに存在し、値を含む)を区別するには
    Optional.absent())
  3. Nullをサポートしないコレクション内のストレージのnull可能参照をラップするには(ただし、これを検討する必要がある他のアプローチがいくつかあります)

最初のケースでは、すべてのnull可能なリターンメソッドでOptionalを返す必要がありますか?

60
lessisawesome

それで、オプションの何が間違っているのでしょうか?

私たちが直面する問題は、JDK 8のオプションオブジェクトがnull参照を取り除くことになるのでしょうか?そして、答えはノーです!だから、中傷者はすぐにその価値を問うことに疑問を投げかけます:それでは、他の手段ではまだできなかったことにとって何が良いのでしょうか?

Null参照の概念がなかったSMLやHaskellのような関数型言語とは異なり、Javaでは、歴史的に存在していたnull参照を単純に取り除くことはできません。これは存在し続けるでしょう。適切な用途があります(例を挙げると 値論理 )。

Optionalクラスの意図は、すべてのnull可能な参照を置き換えることではないことを疑いますが、メソッドのシグネチャを読み取るだけで、オプションの値を期待できるかどうかを判断できる、より堅牢なAPIの作成を支援するためです。それに応じてプログラマにこの値を強制的に使用させます。しかし、最終的に、Optionalは単なる別の参照であり、言語内の他のすべての参照と同じ弱点の影響を受けます(たとえば、null Optionalを返すことができます)。 Optionalが日を節約しないことは明らかです。

Javaはプロジェクトラムダメーリングリストの 白熱した議論 の問題でした。以下のような興味深い議論を聞く中傷者:

  • 他の選択肢が存在するという事実(例えば、IntelliJやEclipseのようなIDES IDEは一連の 独自の注釈 nullabilityの静的分析のために、 JSR-305 @Nullableや@NonNullなどの注釈付き)。
  • 機能的世界 のように使用したい人もいますが、これはJavaでは完全に可能ではありません。SMLやHaskell(パターンマッチングなど)。
  • 他の人は、このイディオムを使用するために 既存のコードをレトロフィットする が不可能であると主張しています(たとえば、nullを返し続けるList.get(Object))。
  • また、オプション値の言語サポートがないために、APIでオプションが 一貫性のない使用 になる可能性のあるシナリオが作成されるという事実について不満を言う人もいます。残りのJava APIは新しいOptionalクラスを使用するために改造することはできません。これはあなたの質問です。オプションタイプをサポートする言語では Ceylonなど または Kotlinのように 、これさえ疑問に思わないでしょう。
  • 説得力のある議論は、プログラマーがオプションオブジェクトのgetメソッドを呼び出し、空の場合、NoSuchElementExceptionを発生させるということです。これは、異なる例外を使用するだけで、nullで発生する問題とほぼ同じです。

したがって、Optionalの利点は本当に疑わしく、おそらく可読性の向上とパブリックインターフェイス契約の実施に制約されるように思われます。

このオプションの機能的なイディオムを採用すると、コードの安全性が高まり、null参照解除の問題が少なくなり、その結果、より堅牢でエラーが発生しにくくなると思います。もちろん、これは完璧なソリューションではありません。結局、オプション参照も誤ってnull参照に設定される可能性がありますが、プログラマはオプションオブジェクトが期待される場所にnull参照を渡さないという慣習に固執すると思います。今日、コレクションまたは配列が予想される場所にnull参照を渡さないようにすることをお勧めします。これらの場合、空の配列またはコレクションを渡すことが正しい方法です。ここでのポイントは、特定の参照に対して、割り当てる値が存在しない可能性があることを明示するために使用できるAPIのメカニズムがあり、ユーザーがAPIによってそれを確認することを強制されることです。

引用 Google Guavaの記事 オプションのオブジェクトの使用について:

「nullに名前を付けることによる読みやすさの向上に加えて、Optionalの最大の利点は、その馬鹿な証拠です。オプションを積極的に展開し、そのケースに対処する必要があるため、プログラムをコンパイルしたい場合は、不在のケースについて積極的に考える必要があります。

そのため、Optionalを使用する範囲を選択するのは、すべてのAPIデザイナー次第です。

Stephen ColebourneやBrian Goetzなどの有力な開発者は、最近、オプションの適切な使用に関する興味深い記事をいくつか公開しています。私は特に次のことが有用だと感じました。

75
Edwin Dalorzo

観察として、アプリケーションを設計する際に考慮しなければならない最も重要な側面の1つは、「null問題」の処理方法を決定することだと思います。この点で、最初のステップは、ヌルの「ソース」の可能性を識別することです。たとえば、プロジェクトで使用されるデータベースまたは外部ライブラリ。次のステップは、問題を「封じ込める」ことです。つまり、問題のあるコードをラップして(オプションを使用)、システム全体でのヌルの伝播をブロックします。
あなたの質問に答えるために、それは依存します...ほとんどの場合、それは不要だと言います。なぜなら、それは価値のない多くの仕事を作成するからです(例えば、私は他のクラス内のプライベートメソッド、またはパッケージプライベートクラスのメソッドを呼び出すメソッド用)、ただし、アプリケーションのさまざまな「懸念」(またはレイヤー)の薄い境界に存在するコード(の署名たとえば、データストアのクエリに使用するインターフェイス/クラス、またはnullプロパティを持つ可能性のあるデータの「転送」に使用されるpojo-DTO、またはより一般的な説明publishedさまざまなモジュールのAPI )異なる懸念を持つ他の領域にヌルを「漏らす」ことを避けるべきです。

8

グアバと比較して、_Java.util.Optional_の厄介な問題の1つは、次のようなメソッドを提供しないことです。

orElse(Optional<T>): Optional<T>

一方、これは_com.google.common.base.Optional_で次のように定義されます

or(Optional<T>): Optional<T>

この特定の機能がないため、Java 8's Optional。

UPDATE:

グアバのor(Optional<T>)は、Java 8オプションとして

optionalA.map(Optional::of).orElse(optionalB)

または

optionalA.map(Optional::of).orElseGet(() -> computeOptionalB)

UPDATE:

Java 9 (最終的に!)では、Optional.or(Supplier<Optional<T>>)を使用できます。

optionalA.or(() -> computeOptionalB)

それはすてきです!

7
Vlad