web-dev-qa-db-ja.com

なぜObjects.requireNonNull()を使うなのでしょうか。

Oracle JDKの多くのJava 8メソッドがObjects.requireNonNull()を使用していることに気付きました。与えられたオブジェクト(引数)がNullPointerExceptionであれば、内部的にnullをスローします。

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

しかしNullPointerExceptionオブジェクトが間接参照されている場合は、nullがスローされます。それで、なぜこの余分なnullチェックをしてNullPointerExceptionを投げるべきなのでしょうか。

1つの明白な答え(または利点)は、それがコードを読みやすくするということです、そして私は同意します。メソッドの冒頭でObjects.requireNonNull()を使用する他の理由を知りたがっています。

109
user4686046

そうすることで、を明示的にすることができるからです。好きです:

public class Foo {
  private final Bar bar;

  public Foo(Bar bar) {
    Objects.requireNonNull(bar, "bar must not be null");
    this.bar = bar;
  }

またはもっと短い:

  this.bar = Objects.requireNonNull(bar, "bar must not be null");

これであなたは知っている

  • whenFooオブジェクトがnew()を使って作成されたとき
  • thenそのbarフィールドはnullでないことが保証されています。

これと比較してみましょう。今日はFooオブジェクトを作成し、明日明日にそのフィールドを使用してスローするメソッドを呼び出します。おそらく、その参照がコンストラクタに渡されたときにその参照がnull昨日だったのは、明日はわかりません。

つまり、このメソッドを明示的に使用してincomingreferenceをチェックすることで、例外が発生した時点を制御することができます。スローされます。そしてたいていの場合、はできるだけ速く失敗したいと思います

主な利点は以下のとおりです。

  • 前述のように、controlledbehavior
  • より簡単なデバッグ - あなたはオブジェクト作成の文脈で投げ出すので。あなたのログ/トレースが何が悪かったのかをあなたに告げる可能性がある時点で!
  • そして上に示したように、このアイデアの真の力はfinalfieldsと共に展開されます。なぜならあなたのクラスの他のコードbarがnullではないと安全に仮定することができるからです - そしてそれ故あなたは他の場所でif (bar == null)チェックを必要としません!
121
GhostCat

フェイルファースト

コードはできるだけ早くクラッシュするはずです。作業の半分を実行してからnullを参照解除し、クラッシュした後でシステムを無効な状態にすることがあります。

これは一般的に「早期に失敗する」または 「高速で失敗する」 と呼ばれます。

63
luk2302

しかし、nullオブジェクトが間接参照されると、NullPointerExceptionがスローされます。それで、なぜ、この余分なnullチェックをしてNullPointerExceptionを投げるべきなのでしょうか。

つまり、問題を即座におよび確実に検出します。

検討してください:

  • あなたのコードが既にいくつかの副作用を実行した後で、参照はメソッドの後半まで使用されないかもしれません
  • このメソッドでは、参照がまったく間接参照されていない可能性があります。
    • それは完全に異なるコードに渡される可能性があります(すなわち、原因とエラーはコード空間で大きく離れています)。
    • それはずっと後に使用される可能性がある(すなわち原因とエラーは時間的にかなり離れている)
  • Null参照有効ですが、意図しない結果になることがあります。

.NETは、NullReferenceExceptionからArgumentNullException( "null値を間接参照しました")を分離することでこれを改善します( "nullとして引数として渡すべきではありませんでした - そしてthis私はJavaが同じことをしたかったのですが、たとえNullPointerExceptionがあっても、エラーが可能な限り早い時点で投げられるならコードを直すことはずっと簡単です検出されます。

28
Jon Skeet

メソッド内の最初のステートメントとしてrequireNonNull()を使用すると、今すぐ例外の原因を特定することができます。
スタックトレースは、メソッドの入力直後に例外がスローされたことを明確に示しています 呼び出し元がその要件/契約を尊重していないため
nullオブジェクトを別のメソッドに渡すと、実際には一度に例外が発生しますが、nullオブジェクトに対する特定の呼び出しで例外がスローされるため、問題の原因を理解するのが複雑になる場合があります。

4
davidxxx

ちなみに、Object#requireNotNullがいくつかのjreクラス自体の中でJava-9の前に実装される前にわずかに異なる前に、これは速く失敗します。ケースを仮定します:

 Consumer<String> consumer = System.out::println;

Java-8ではこれは次のようにコンパイルされます(関連する部分のみ)

getstatic Field Java/lang/System.out
invokevirtual Java/lang/Object.getClass

基本的にはyourReference.getClassのような操作 - yourRefercenceがnullの場合は失敗します。

Jdk-9では、同じコードがコンパイルされるのと同じように状況が変わりました。

getstatic Field Java/lang/System.out
invokestatic Java/util/Objects.requireNonNull

あるいは基本的にObjects.requireNotNull (yourReference)

1
Eugene

基本的な使用法は、NullPointerExceptionをすぐにチェックしてスローすることです。

同じ要件を満たすためのもう1つの優れた代替手段(ショートカット)は、 @ NonNull lombokによる注釈です。

0