web-dev-qa-db-ja.com

プログラムでNullPointerExceptionをスローしても大丈夫ですか?

事後条件がある場合、メソッドの戻り値がnullであってはなりません。何ができますか?

私はそれをできた

assert returnValue != null : "Not acceptable null value";

しかし、アサーションはオフにすることができます!

だから大丈夫ですか

if(returnValue==null)
      {
           throw new NullPointerException("return value is null at method AAA");
      }

または、そのような条件にユーザー定義の例外(NullReturnValueExceptionなど)を使用する方が良いでしょうか?

43
stratwine

JVMが自動的に行う前に、特にヌル引数の場合、NPEをできるだけ早くスローしても問題はありません。これについてはいくつかの議論があるようですが、これを行うJava SEライブラリには多くの例があります。自分で投げます。

しかし、私は脱線します。この質問は何か違うものです。あなたは、戻り値がnullであってはならないことを示す事後条件について話している。この場合、確かにnullはバグがあることを意味しますメソッド内

これをどのように文書化しますか? 「戻り値が予期せずnullである場合、このメソッドはNullPointerExceptionをスローします」これがどのように起こるか説明せずに?いいえ、ここではアサーションを使用します。例外は、おそらく発生する可能性のあるエラーに使用する必要があります。メソッド内に何か問題がある場合に発生する可能性のあるものはカバーしません。

41
waxwing

NullPointerExceptionを自分で投げないことをお勧めします。

これを行わない主な理由は、ThorbjørnRavn Andersenが以下のコメントで述べているように、「実際の悪いNPE」と意図的にスローされたNPEを混在させたくないということです。

したがって、「有効な」NPEを認識できると確信するまで、IllegalArgumentExceptionが有効な引数ではないことをAPIユーザーに伝えたい場合は、nullを使用することをお勧めします。値。無効なnullパラメータが渡されたときのメソッドの動作を文書化する必要があります。

別の(より現代的な私見)オプションは、引数の近くで_@NotNull_注釈を使用することです。 @ NotNullアノテーションの使用に関する記事 です。

前にも述べたように、NPEを投げてもあなたやチームメイトの混乱を招かない場合もあります。NPEの原因は明確で認識できるものでなければなりません。

たとえば、Guavaなどの前提条件モジュールでライブラリを使用する場合、checkNotNull()のようなメソッドを使用することが、不正に渡されたnullを処理するための好ましい方法であることがわかります。

checkNotNull(arg, msg)はNPEをスローしますが、スタックトレースからPreconditions.checkNotNull()によって生成されたことが非常に明確であり、未知のバグではなく、予想される動作です。

60
Roman

NullPointerExceptionがJavaで予期しないnull値を伝える慣用的な方法であることを考えると、自家製のものではなく標準のNullPointerExceptionをスローすることをお勧めします。また、システムの例外タイプが存在する場合には、最も驚きの原則から、独自の例外タイプを発明しないことを示唆していることに留意してください。

アサーションはデバッグには適していますが、特定の条件を処理する必要がある場合は適切ではないため、実際にはエラー条件を処理するのに適した方法ではありません。

28
Timo Geusch

NullPointerExceptionの問題は、forgetが何かがnullかどうかをチェックしたり、nullの間違った引数を与えたりするべきではないときに発生することです。

私の経験から、Javaプログラマーはこの例外がコードのバグによって引き起こされていることを非常に早く知っているので、手動でスローするとmostが非常に混乱します。IllegalArgumentException受け入れられない引数(nullなど、nullであってはならないもの)を渡す場合は、より良いアイデアです。

また、別のヒューリスティックもトリガーします。 NPE =ここでコードにエラーが発生しました。IllegalArgumentException =メソッドに指定されたオブジェクトが無効です。

一方、javadocは次のことを伝えます。

アプリケーションは、このクラスのインスタンスをスローして、
nullオブジェクトのその他の違法な使用。

したがって、NPEのスローはlegalになりますが、これは一般的な方法ではないため、IllegalArgumentExceptionをお勧めします。

11
Danubian Sailor

NullPointerExceptionをスローすることに対する普遍的な法則は確かにありませんが、そのような抽象化された例で実際にすべきかどうかを答えるのは難しいです。あなたがしたくないことは、人々をNullPointerExceptionをキャッチしようとする立場に追い込むことです。このようなコード(実際の例、私は誓います):

catch (NullPointerException npe) {
  if (npe.getMessage().equals("Null return value from getProdByCode") {
    drawToUser("Unable to find a product for the product type code you entered");
  } 
}

あなたが何か間違ったことをしている確実な指標です。したがって、null戻り値が実際に通信できるシステム状態のインジケータである場合、その状態を通信する例外を使用します。 nullポインタをチャックするためだけに参照をnullチェックすることが理にかなっていると思うケースは多くありません。通常、次のコード行は、とにかくヌルポインター(またはより有益なもの)をチャックします!

7
Affe

NullPointerExceptionの使用は問題ないと思います。if説明を覚えています。それが調査対象者の仕事です(行番号が変わる場合があります)。また、特別な場合にメソッドがnullポインター例外をスローすることを文書化することを忘れないでください。

メソッドパラメータを最初から確認する場合、throw new IllegalArgumentException("foo==null")も受け入れられます。

http://pmd.sourceforge.net/pmd-5.0.1/rules/Java/strictexception.html
"NullPointerExceptionsのスローは避けてください。ほとんどの人は仮想マシンがスローしたと想定するため、これらは混乱を招きます。代わりにIllegalArgumentExceptionを使用することを検討してください。

4
Gab

NullPointerExceptionのJavaDoc 状態:

オブジェクトが必要な場合にアプリケーションがnullを使用しようとするとスローされます。これらには以下が含まれます:

* Calling the instance method of a null object.
* Accessing or modifying the field of a null object.
* Taking the length of null as if it were an array.
* Accessing or modifying the slots of null as if it were an array.
* Throwing null as if it were a Throwable value. 

アプリケーションは、このクラスのインスタンスをスローして、nullオブジェクトの他の不正使用を示す必要があります。

事後条件に違反することは違法行為だと思います。ただし、どの例外を使用するかはそれほど重要ではないと思います。なぜなら、到達できないコードパスについて話しているためです(できればそうなることを願っています)。その名前は、誰も見ることのないログファイルのエントリの異なる表現です。

対照的に、投稿条件に違反する可能性が高いと思われる場合は、メソッドが呼び出された引数など、より多くのデバッグ情報を含めることをお勧めします。

3
meriton

戻り値をnullにできないメソッドコントラクトを記述する場合は、nullを返さないようにしてください。しかし、これはNullPointerExceptionではありません。返さなければならない値がnullである場合、呼び出し元が間違った引数( IllegalArgumentException )を与えていることは明らかであり、有効な状態ではありません( IllegalStateException =)、またはNullPointerException(通常はプログラミングエラーを示します)以外の、より有意義な例外条件が発生しました。

3
Tim Bender

私がO'Reilly's Java)A = Nutshellと呼んだ本には、NullPointerExceptionの定義がリストされています。

フィールドへのアクセスまたはnullオブジェクトのメソッドの呼び出しの試行を通知します。

Nullを返すことはこれらのいずれでもないため、独自の例外を記述する方が適切だと思います。

1
Rafe Kettler

多くの場合、ロジックが深くなる前にNPEをスローすることは非常に良い考えです。そのため、呼び出し側のプログラマーは、何がヌルであるかを理解するのに苦労します。 addListener()メソッドは良い例です。

情報のないダウン投票にもかかわらず、JDKにはこれを正確に行う多くのメソッドがあります。

1
user207421

はいぜったいに。

JDK7でさえこれを解決します。 Objects#requireNonNull を参照してください

void doWith(final Object mustBeNotNull) {

    /*
    // bush style
    if (mustBeNotNull == null) {
        throw new IllegalArgumentException("mustBeNotNull must not be null");
    }
    */

    /*
    // obama style
    if (mustBeNotNull == null) {
        throw new NullPointerException("mustBeNotNull must not be null");
    }
    */

    // kangnam style
    Objects.requireNonNull(mustBeNotNull, "mustBeNotNull must not be null");

    assert mustBeNotNull != null;
}
0
Jin Kwon

Javaバースでは、nullは常にオブジェクトを期待するときに有効な値です。このような不可能な投稿条件を避ける方が良いでしょう。本当にnullを守れない場合は、メソッドを作り直してプリミティブを返す必要があります。

0
CurtainDog

NPEはコードのバグであり、スローすべきではありませんが、開発者は予期しないnullを修正する必要があるという以前の回答の主張に同意します。ただし、この状態はテストによってほとんどの場合防止できます。

質問は7年前に聞かれましたが、Java 8にオプションがあり、この機能によりNPEを防ぐことができます。

私の心にある最後の1つの解決策は、nullのオブジェクトをチェックし、それが等しい場合、何が起こったのか説明して独自の例外をスローすることです。

0
Peter S.

ジョシュア・ブロッホがかつて言ったように:「ヌルは吸う!」 :)私の顔がnullであるときはいつでも、グアバが提供するOptionalを使用しようとします。利点は私には多数あります。

0
Eugene

はい、それは大丈夫ですが、私はそれがちょうどそれが起こるようにするへのより良い決定だと主張します。

Javaプログラマーとnullの問題は、人々がC/C++のバックグラウンドから来ているということです。ここで、NULLはかなり異なることを意味します。C/ C++では、NULL(またはワイルド)ポインターの逆参照は深刻です奇妙なメモリの問題やプログラムのクラッシュを引き起こす可能性のある問題(明らかに望ましくありません)。C/ C++の考え方から抜け出すことができ、この状態を処理するこの余分なレイヤー、JVMがあることに気付いた場合、 NULLについて少し違った考え方を始めます。

C++には、たとえば、NULLを割り当てることのできない参照があります。 Javaには参照はありませんが、JavaオブジェクトパラメータはC++ポインタのように動作します。しかし、Javaではメソッドが暗黙的に[〜#〜] not [〜#〜]パラメータのnull値を受け取る必要があります!それで、私たちは何をしますか?

Javaでnullを処理する場合の問題は、C++ではnullチェック[〜#〜] everywhere [〜#〜]となることです。参照を取得するメソッドを宣言するだけで、NULLを受け入れないことを明示的に宣言します。まもなく、すべてのメソッドは、その時点でプログラムの状態をアサートするためだけに健全性チェックを行わなければなりません。

メソッドのデフォルトのコントラクトでは、パラメーター値に対してnullは無効であるという仮定の下で作業する方がはるかに良い状態です。

どうして?さて、そのようなメソッドがパラメーター値としてnullを受け取ったときに何が起こるか見てみましょう。 a)動作の一部として値を逆参照しないので、おそらく大丈夫です。この場合、何も起こりません。 b)値は逆参照されます。この場合、JVMからの振る舞いはまさに私たちが望むものです。パラメーター値がnullであるためにメソッドのコントラクトに違反していることを示す例外がスローされ、スタックトレースが含まれます。この方法で値が使用されるメソッドの行。

ログにNPEが表示されると、「誰かがめちゃくちゃになった」ことを意味すると考えるため、人々はNPEに問題を持ちます。しかし、これについて少し考えてみましょう。実際に、予想される動作とは対照的に、ファックアップの指標としてのNPEの違いは何ですか?予想される動作としてNPEを使用する主な違い(および利点)は、NPEが発生したメソッドではなく、メソッドのコントラクトに違反している呼び出し元を指すことです。これは、はるかに役立つ情報です。単純にnullをチェックして別の例外をスローする場合、実際に呼び出し元がメソッドの規約に違反しているときに、観測された動作が予期されるエラーであるという誤った印象を受ける可能性があります。おめでとうございます、あなたは呼び出し元がメソッドを呼び出す際にどのように台無しになるかを正しく予測しました-しかし、あなたがやったことは例外の本当の原因が何であるか迷っています-またはせいぜい、あなたは2つの異なる例外クラスを使用しています同じことを示し、その間に不必要なゴミでコードを大量に汚すために。

結局のところ、人々はNPEをタブーと見なします。文字通り、恥ずかしさがあるので、人々はそれを投げることを許しません-値がnullになる場所を推測できなかったのであなたが十分に賢くないかのように。まあ、私はあなたたちのためにニュースを得ました、あなたは同じことをするためにより多くの役に立たないコードを書いているだけです。

いくつかの例:

public void foo(Object o) {
  if (o == null) {
    throw new IGotchaException("HA! You're an IDIOT! I knew it!!");
  }
  o.bar();
}

public void foo(Object o) {
  o.bar();
}

^政治的に異なる。機能的にはそれほどではありません。

public void foo(int a, long b, double c, Object o) {
  if (o == null) {
    throw new IllegalArgumentException("Oh. Uh. Well, you've passed me null here. I... I'm not sure where to go from here because this object is kind of required for this function to do what it's supposed to do. Soooo... wouldja mind reworking your code a little bit so as to not pass null to this function as a parameter?! That'd be great thanks. Oh by the way, it's cause we deference o 40 lines below here");
  }
  // ...
  o.doSomethingWithA(a);
}

public void foo(int a, long b, double c, Object o) {
  // ...
  o.doSomethingWithA(a);
  // NullPointerException, line 40, e.g. it wasn't OK to pass null for o you lunkhead
}

^たぶん多くの迷​​惑なコードを犠牲にして、いくつかのCPUサイクルを節約します。ただし、2番目のケースでは比較が少なくなります。

public void foo(Object a, Object b, Object c, Object d) {
  if (a == null) throw IllegalArgumentException("jackass");
  if (b == null) throw IllegalArgumentException("jackass");
  if (c == null) throw IllegalArgumentException("jackass");
  // But d is totally OK!
  // ...
  c.setSomeValueThatMayBeNull(d);
}

public void foo(Object a, Object b, Object c, Object d) {
  // ...
  c.setSomeValueThatMayBeNull(d);
  // Throws null pointer exception if c is null, but not if d is null. Which is basically the same as above
}

^契約は、メソッドの最初の例外ケースではなく、ステートメントから暗黙的です。他の欠点はありません。

public void foo(Object o) {
  if (o == null) {
    doTheBoogie();
  } else {
    doTheRobot();
  }
}

^悪い

public void foo(Object o, int b) {
  Bar value = o.findSomethingWhichMayExist(b);
  if (value == null)
    return;
  value.doSomething();
}

^ null戻り値を使用して、値がないことを示します。 OK。

NPEに問題があるもう1つの理由は、例外の処理方法がわからないためです。 NPEは決して目立つものであってはなりません。適切な動作は、RunmainExceptionをキャッチすることです。おそらく、「main」の前にそれをトラップして報告するコールスタックで、はるかに高い(または表示方法に応じて低い)レベルで実行されます。つまり、より回復力が必要で、NPEが発生したときにcrashだけではいけないようなプログラムを開発していると仮定します。

結論:メソッドパラメーターにnull値を渡すことが有効であることを期待しないでください。また、明示的にnullを受け入れ、それを有効な値として扱うメソッドのコントラクトを作成しないでください。しかし、allow nullポインター例外が発生し、コードが失敗するか、問題ではない場合は当然失敗します。

0
Erich

IMOでは、手動でNullPointerExceptionをスローしないでください。呼び出しルーチンは、説明をチェックしないと、実際のNullPointerExceptionか手動のNullPointerExceptionかを知りません。この場合、呼び出し側のメソッドがこの例外からfrmを正しく回復できるように、問題に近い独自の例外をロールバックしたいようです。たぶん、PostConditionExceptionは多くの状況で十分に一般的です。

0

事後条件がある場合、メソッドの戻り値がnullであってはなりません。何ができますか?

事後条件とは、条件が満たされない場合、問題のメソッドにバグがあることを意味します。これをコードで表現する方法は、事後条件でassertを使用することです。 NullPointerExceptionIllegalStateExceptionなどの例外を直接スローすることは、少し誤解を招くため、誤ったガイドになります。

NullPointerExceptionをプログラムでスローしても大丈夫ですか?

NPEのJava API docはyesと言っていますが、このページで与えられた投票から判断すると、開発者の3:1の過半数がnoと言っています。あなたのワークグループで。

APIドキュメントには、コードが何らかの方法(メソッドの呼び出しやフィールドへのアクセスなど)のオブジェクトを必要とするnull参照で操作を呼び出そうとし、nullがそうではないため、JVMがNPEを上げるケースが最初にリストされていますオブジェクト。それはそれから述べます:

アプリケーションは、このクラスのインスタンスをスローして、nullオブジェクトの他の不正使用を示す必要があります。

興味深いことに、nullはここでは「オブジェクト」と呼ばれますが、そうではありません。これは、NullPointerExceptionという名前が、ポインターを持たない言語にとって奇妙だということを思い出させてくれます。 (おそらく、Microsoft .NETクラスライブラリのようにNullReferenceExceptionになっているはずです。)

それでは、この点でAPIドキュメントを却下する必要がありますか?そうは思いません。クラスライブラリは、ドキュメントで説明されているように、たとえばJava.nio.channelsなどのNPEを使用します。

特に断りのない限り、null引数をこのパッケージのクラスまたはインターフェイスのコンストラクターまたはメソッドに渡すと、NullPointerExceptionがスローされます。

これは、JVMによって生成されたNPEではなく、どの引数がnull"in" is null!など)であるかを示すエラーメッセージが添付されたコード化されたNPEです。 (このコードは、javap -c -p Java.nio.channels.Channels | moreを実行し、private static void checkNotNullを探すことで確認できます。)この方法でNPEを使用するクラスは、本質的にIllegalArgumentExceptionの特殊なケースとして見られます。

したがって、これを少し調べて考えた後、これがNPEの適切な使用であることがわかりました。したがって、APIドキュメントと少数のJava開発者( Javaクラスライブラリと同じように、つまり顕著にエラーメッセージを提供することにより、独自のコードでNPEを使用する権利と権利の両方があること] JVMで生成されたNPEにないため、2種類のNPEを区別するのに問題はありません。

とにかくNPEがさらに先にスローされるというマイナーポイントに対処するには:ディスクまたはネットワークI/O(および遅延)を含むJVMをプログラムで続行させるのではなく、エラーを早期にキャッチすることは非常に理にかなっています)、および不必要に大きなスタックトレースを生成します。

0
Lumi