565

プロパティの単純なセッター メソッドがありnull、この特定のプロパティには適していません。私はいつもこの状況で引き裂かれてきました: IllegalArgumentException、またはを投げるべきNullPointerExceptionですか? javadocs から、どちらも適切に見えます。ある種の理解された基準はありますか?それとも、これは好きなようにすべきことの 1 つにすぎず、どちらも本当に正しいのでしょうか?

4

26 に答える 26

430

次の理由により、(NPE)IllegalArgumentExceptionではなく (IAE)を使用する必要があります。NullPointerException

まず、NPE JavaDocには、NPE が適切なケースが明示的にリストされています。が不適切に使用されると、これらすべてがランタイムによってスローされることに注意してください。null対照的に、IAE JavaDocはこれ以上明確ではありません。「メソッドに不正または不適切な引数が渡されたことを示すためにスローされます。」うん、それはあなたです !

次に、スタック トレースに NPE が表示された場合、何を想定しますか? おそらく、誰かがnull. IAE が表示された場合、スタックの一番上にあるメソッドの呼び出し元が不正な値を渡したと想定します。繰り返しますが、後者の仮定は真実ですが、前者は誤解を招きます。

第 3 に、IAE はパラメーターを検証するために明確に設計されているため、例外のデフォルトの選択肢として IAE を想定する必要があります。代わりに NPE を選択する理由は何ですか? 確かに異なる動作のためではありません.コードを呼び出すことで、IAEとは別にNPEをキャッチし、結果として何か違うことをすることを本当に期待していますか? より具体的なエラー メッセージを伝えようとしていますか? ただし、他のすべての不正なパラメーターの場合と同様に、例外メッセージ テキストでそれを行うことができます。

第 4 に、他のすべての不正なパラメータ データは IAE になるため、一貫性を保つ必要はありません。null違法な引数が非常に特殊で、他のすべてのタイプの不正な引数とは別の例外に値するのはなぜですか?

最後に、Java API の一部がこの方法で NPE を使用しているという他の回答で与えられた議論を受け入れます。ただし、Java API は、例外の種類から命名規則まですべてに一貫性がないため、Java API (のお気に入りの部分) をやみくもにコピーするだけでは、これらの他の考慮事項を打ち負かすのに十分な議論ではないと思います。

于 2008-09-06T18:29:07.520 に答える
313

許可された値になりIllegalArgumentExceptionたくない場合は が呼び出され、であることが判明した変数を使用しようとすると がスローされるようです。nullNullPointerExceptionnull

于 2008-08-06T19:29:24.427 に答える
167

標準はを投げることNullPointerExceptionです。一般的に間違いのない「EffectiveJava」では、これについて、項目42(第1版)、項目60(第2版)、または項目72(第3版)「標準例外の使用を優先する」で簡単に説明しています。

「間違いなく、すべての誤ったメソッド呼び出しは、不正な引数または不正な状態に要約されますが、特定の種類の不正な引数および状態には、他の例外が標準的に使用されます。呼び出し元がnull値が禁止されているパラメーターでnullを渡した場合、規則により次のようになります。 IllegalArgumentExceptionではなくNullPointerExceptionがスローされます。」

于 2008-08-11T20:05:18.527 に答える
145

Java 7 のメソッドIllegalArgumentExceptionに気付いた今日まで、私は null パラメーターをスローすることに賛成していました。java.util.Objects.requireNonNull

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

できるよ:

Objects.requireNonNull(param);

NullPointerException渡したパラメータが である場合は、がスローされますnull

そのメソッドが真ん中にあることを考えると、その存在は、スローが「Java のやり方」であるjava.utilことをかなり強く示していると思います。NullPointerException

何となく決まってると思います。

ハードデバッグに関する議論は偽物であることに注意してください。もちろん、NullPointerException何がnullで、なぜnullであってはならないかを伝えるメッセージを提供できるからです。と同じようにIllegalArgumentException

の追加の利点の 1 つNullPointerExceptionは、非常にパフォーマンスが重要なコードでは、null の明示的なチェック (およびわかりやすいエラー メッセージ)を省き、null でメソッドを呼び出したときに自動的に取得NullPointerExceptionされる に依存できることです。NullPointerExceptionパラメータ。メソッドをすばやく呼び出す (つまり、フェイル ファスト) とすれば、基本的に同じ効果が得られますが、開発者にとってユーザー フレンドリーとは言えません。ほとんどの場合、明示的にチェックして、どのパラメーターが null であったかを示す有用なメッセージをスローする方がよいでしょう。

于 2011-11-19T18:42:13.277 に答える
74

私は JDK ライブラリの設計に従う傾向があり、特に Collections と Concurrency (Joshua Bloch や Doug Lea など、堅実な API の設計方法を知っている) に注目しています。とにかく、JDK の多くの API は積極的にNullPointerException.

たとえば、Map.containsKey状態の Javadoc は次のとおりです。

@throws NullPointerException キーが null で、このマップが null キーを許可しない場合 (オプション)。

独自の NPE をスローすることは完全に有効です。規則では、null であったパラメーター名を例外のメッセージに含めます。

パターンは次のとおりです。

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

何をするにしても、悪い値が設定されないようにして、後で他のコードがそれを使用しようとしたときに例外をスローしないでください。それはデバッグを悪夢にします。常に「フェイル ファスト」の原則に従う必要があります。

于 2008-08-08T20:35:04.007 に答える
47

ジェイソン・コーエンの議論はよく提示されていたので、賛成票を投じました。段階的に分解してみましょう。;-)

  • NPE JavaDocには、 「null オブジェクトのその他の違法な使用」と明示的に記載されています。ランタイムが null に遭遇してはならない状況にのみ限定されていれば、そのようなすべてのケースははるかに簡潔に定義できます。

  • 間違ったことを仮定すると仕方がありませんが、カプセル化が適切に適用されていると仮定すると、null が不適切に逆参照されたかどうかと、メソッドが不適切な null を検出して例外を発生させたかどうかを実際に気にしたり、注意したりする必要はありません。

  • 複数の理由から、 IAEよりもNPEを選択します

    • 違法な操作の性質についてより具体的です
    • null を誤って許可するロジックは、不正な値を誤って許可するロジックとは大きく異なる傾向があります。たとえば、ユーザーが入力したデータを検証している場合、受け入れられない値を取得した場合、そのエラーの原因はアプリケーションのエンド ユーザーにあります。null を取得した場合、それはプログラマ エラーです。
    • 無効な値は、スタック オーバーフロー、メモリ不足エラー、解析例外などの原因となる可能性があります。実際、ほとんどのエラーは通常、ある時点で、何らかのメソッド呼び出しで無効な値として存在します。このため、私は IAE をRuntimeException のすべての例外の中で最も一般的なものと考えています。
  • 実際には、他の無効な引数によって、あらゆる種類の例外が発生する可能性があります。UnknownHostExceptionFileNotFoundException、さまざまな構文エラー例外、IndexOutOfBoundsException、認証失敗など。

一般に、NPE はフェイル ファストの原則に従わないコードと関連付けられてきたため、NPE は非常に悪意のあるものだと感じています。それに加えて、JDK が NPE にメッセージ文字列を入力できなかったことは、十分に根拠のない強い否定的な感情を生み出しました。実際、ランタイムの観点から見た NPE と IAE の違いは厳密には名前です。その観点から、名前を正確に使用すればするほど、発信者に明確な情報を提供できます。

于 2009-12-09T06:07:52.040 に答える
21

「聖戦」風の質問です。言い換えれば、どちらの選択肢も良いのですが、人には自分の好みがあり、それを命がけで守ります。

于 2008-10-17T13:31:45.627 に答える
18

それがsetterメソッドでありnull、それに渡されている場合は、をスローする方が理にかなっていると思いますIllegalArgumentExceptionNullPointerException実際に . を使用しようとしている場合は、null.

したがって、それを使用していて、それnullNullPointer. それが渡されていて、それがnull,の場合IllegalArgument.

于 2008-08-06T19:31:11.070 に答える
10

Apache Commons Lang には、ここで説明した多くのことを行うNullArgumentExceptionがあります。これは IllegalArgumentException を拡張し、その唯一のコンストラクターは非 null であるべき引数の名前を取ります。

NullArgumentException や IllegalArgumentException のようなものをスローすると、例外的な状況をより正確に説明できると思いますが、同僚と私は、この件に関する Bloch のアドバイスに従うことにしました。

于 2009-07-02T04:47:14.430 に答える
7

実際、IllegalArgumentException または NullPointerException をスローする問題は、私の謙虚な見解では、Java での例外処理の理解が不十分な少数派にとっては「聖戦」にすぎません。一般に、ルールは単純で、次のとおりです。

  • 引数の制約違反は、デバッグがはるかに困難な不正な状態を回避するために、できるだけ早く (-> 高速失敗) 示す必要があります。
  • 何らかの理由で無効な null ポインターの場合は、NullPointerException をスローします。
  • 不正な配列/コレクション インデックスの場合は、ArrayIndexOutOfBounds をスローします
  • 負の配列/コレクション サイズの場合は、NegativeArraySizeException をスローします。
  • 上記でカバーされていない不正な引数の場合、および別のより具体的な例外タイプがない場合は、ゴミ箱として IllegalArgumentException をスローします
  • 一方、なんらかの正当な理由でファスト フェイルによって回避できなかった WITHIN A FIELD の制約違反の場合は、IllegalStateException またはより具体的なチェック済み例外としてキャッチして再スローします。この場合、元の NullPointerException、ArrayIndexOutOfBounds などを渡さないでください。

あらゆる種類の引数制約違反を IllegalArgumentException にマッピングする場合には、少なくとも 3 つの非常に正当な理由があります。

(1) プログラマーは、引数制約違反のすべてのケースが IllegalArgumentException になると安全に想定することはできません。これは、標準クラスの大多数が、より具体的な種類の例外が利用できない場合、この例外をごみ箱として使用するためです。API で引数の制約違反のすべてのケースを IllegalArgumentException にマップしようとしても、クラスを使用するプログラマーのフラストレーションにつながるだけです。標準ライブラリはほとんどの場合、あなたのルールに違反するさまざまなルールに従っており、ほとんどの API ユーザーもそれらを使用するからです!

(2) 例外をマッピングすると、実際には、単一継承によって引き起こされる別の種類の異常が発生します。すべての Java 例外はクラスであるため、単一継承のみをサポートします。したがって、サブクラスはどちらか一方からしか継承できないため、真に NullPointerException と IllegalArgumentException の両方である例外を作成する方法はありません。したがって、null 引数の場合に IllegalArgumentException をスローすると、プログラムがプログラムで問題を修正しようとするたびに、API ユーザーが問題を区別するのが難しくなります。

(3) マッピングは、実際にはバグ マスキングの危険を生み出します。引数の制約違反を IllegalArgumentException にマップするには、制約された引数を持つすべてのメソッド内で外側の try-catch をコーディングする必要があります。ただし、この catch ブロックで単に RuntimeException をキャッチすることは問題外です。これは、引数の制約違反が原因ではない場合でも、あなたの内部で使用されている libery メソッドによってスローされた文書化された RuntimeExceptions を IllegalArgumentException にマッピングするリスクがあるためです。したがって、非常に具体的にする必要がありますが、その努力でも、別の API の文書化されていない実行時例外 (つまりバグ) を誤って API の IllegalArgumentException にマップしてしまうというケースから保護することはできません。

一方、標準的な慣行では、ルールは単純なままであり、例外の原因はマスクされておらず、具体的なままです。メソッドの呼び出し元にとっても、ルールは簡単です。 - 不正な値を渡したために何らかの種類の文書化されたランタイム例外が発生した場合は、デフォルトで呼び出しを繰り返すか (この特定の例外が必要なため)、コードを修正します。 - 一方、特定の引数セットで発生することが文書化されていない実行時例外に遭遇した場合は、メソッドのメーカーにバグ レポートを提出して、コードまたはドキュメントが修正されていることを確認してください。

于 2012-12-31T17:44:57.683 に答える
7

言われていることにこれ以上同意できませんでした。早く失敗し、早く失敗しましょう。かなり良い例外のマントラ。

どの例外をスローするかという問題は、主に個人的な好みの問題です。私の考えでは、 IllegalArgumentException は、メソッドの実行中に生成された可能性のある値ではなく、メソッドに渡した引数に問題があることを示しているため、NPE を使用するよりも具体的に見えます。

私の2セント

于 2008-08-22T11:11:35.980 に答える
7

主観的な質問として、これはクローズする必要がありますが、まだ開いているため:

これは私の以前の職場で使用されていた社内ポリシーの一部であり、非常にうまく機能しました。全部記憶なので正確な文章は覚えていません。彼らがチェック例外を使用しなかったことは注目に値しますが、それは質問の範囲を超えています。彼らが実際に使用した未チェックの例外は、主に 3 つのカテゴリに分類されました。

NullPointerException: 意図的にスローしないでください。NPE は、null 参照を逆参照するときに VM によってのみスローされます。これらがスローされないように、可能な限りの努力を払う必要があります。@Nullable および @NotNull をコード分析ツールと組み合わせて使用​​して、これらのエラーを検出する必要があります。

IllegalArgumentException: 渡された引数に関してエラーを識別および説明できるように、関数への引数が公開ドキュメントに準拠していない場合にスローされます。OP の状況は、このカテゴリに分類されます。

IllegalStateException: 関数が呼び出され、その引数が渡された時点で予期されていないか、メソッドがメンバーであるオブジェクトの状態と互換性がない場合にスローされます。

たとえば、長さのあるもので使用される IndexOutOfBoundsException の 2 つの内部バージョンがありました。IllegalStateException のサブクラスの 1 つで、インデックスが長さよりも大きい場合に使用されます。もう 1 つは IllegalArgumentException のサブクラスで、インデックスが負の場合に使用されます。これは、オブジェクトにさらにアイテムを追加でき、引数が有効であるのに対し、負の数は無効であるためです。

私が言ったように、このシステムは非常にうまく機能し、なぜこの違いがあるのか​​を誰かが説明する必要がありました。何が問題だったのかを突き止めれば、そのエラーをキャッチする場所を特定し、追加のデバッグ情報を作成できます。」

NullPointerException: Null ケースを処理するか、NPE がスローされないようにアサーションを入れます。アサーションを入れると、他の 2 つのタイプの 1 つにすぎません。可能であれば、最初からアサーションがあったかのようにデバッグを続けます。

IllegalArgumentException: 呼び出しサイトに問題があります。渡された値が別の関数からのものである場合は、誤った値を受け取っている理由を調べてください。引数の 1 つを渡す場合、期待どおりに返されない関数が見つかるまで、エラーがコール スタックをチェックします。

IllegalStateException: 関数を正しい順序で呼び出していません。引数の 1 つを使用している場合は、それらを確認し、問題を説明する IllegalArgumentException をスローします。その後、問題が見つかるまでチークをスタックに対して伝播できます。

とにかく、彼の要点は、IllegalArgumentAssertions のみをスタックにコピーできるということでした。IllegalStateExceptions または NullPointerExceptions は関数と関係があるため、スタックに伝播する方法はありません。

于 2016-09-23T10:07:12.967 に答える
6

IllegalArgumentException(String message)を使用してパラメーターを無効と宣言し、可能な限り詳細を提供する場合に受け入れられる方法...つまり、パラメーターがnullであることが判明し、例外がnullでない場合は、次のようにします。このような:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

「NullPointerException」を暗黙的に使用する理由は事実上ありません。NullPointerExceptionは、null参照( toString()など)でコードを実行しようとしたときにJava仮想マシンによってスローされる例外です。

于 2008-08-11T19:43:49.210 に答える
6

null引数 (またはカスタム型)に排他的な例外をスローすると、NullPointerException自動nullテストの信頼性が向上します。この自動テストは、グアバの のように、リフレクションと一連のデフォルト値を使用して実行できますNullPointerTester。たとえばNullPointerTester、次のメソッドを呼び出そうとします...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

...引数の 2 つのリスト:"", nullnull, ImmutableList.of(). これらの呼び出しのそれぞれが期待される をスローすることをテストしますNullPointerException。この実装では、nullリストを渡しても は生成されませNullPointerException。ただし、デフォルトの文字列 をたまたま使用しているIllegalArgumentExceptionため、たまたま が生成されます。値のみを期待する場合、バグをキャッチします。期待している場合は、それを逃します。NullPointerTester""NullPointerTesterNullPointerExceptionnullIllegalArgumentException

于 2012-11-09T16:30:07.017 に答える
5

一般に、開発者はNullPointerExceptionをスローしないでください。この例外は、コードが値がnullである変数を逆参照しようとしたときにランタイムによってスローされます。したがって、メソッドがnullを明示的に禁止したい場合は、null値が発生してNullPointerExceptionが発生するのではなく、IllegalArgumentExceptionをスローする必要があります。

于 2008-09-05T10:34:05.583 に答える
5

一部のコレクションは、ではなくnullを使用して拒否されると想定しています。たとえば、を含むセットを拒否するセットと比較すると、最初のセットは他のセットを呼び出し、その-をキャッチしますが、はキャッチしません。(私はの実装を見ています。)NullPointerExceptionIllegalArgumentExceptionnullnullcontainsAllNullPointerExceptionIllegalArgumentExceptionAbstractSet.equals

このようにチェックされていない例外を使用することはアンチパターンであり、含むコレクションと含めるnullことができないコレクションを比較することnullは、実際に例外null生成する可能性のあるバグである可能性が高い、またはコレクションを入れることは悪い考えであると合理的に主張できます。 。それでも、そのような場合に例外をスローする必要があると言うつもりがない限り、特定の状況では必要であるが他の状況では必要とされequalsないことを覚えておくNullPointerException必要があります。(「'c'の後を除いてNPEの前のIAE...」)

于 2012-11-09T16:18:38.267 に答える
4

二分法...それらは重複していませんか?全体の重複しない部分だけが二分法を作ることができます。私の考えでは:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
于 2012-04-17T17:15:09.600 に答える
4

他の不正な引数からNull引数を選び出したかったので、NullArgumentExceptionという名前のIAEから例外を派生させました。例外メッセージを読む必要さえなくても、null引数がメソッドに渡されたことを知っており、メッセージを読むことで、どの引数がnullであるかを見つけます。IAEハンドラーでNullArgumentExceptionをキャッチしますが、ログで違いをすばやく確認できます。

于 2009-01-17T00:13:16.980 に答える
-1

The definitions from the links to the two exceptions above are IllegalArgumentException: Thrown to indicate that a method has been passed an illegal or inappropriate argument. NullPointerException: Thrown when an application attempts to use null in a case where an object is required.

The big difference here is the IllegalArgumentException is supposed to be used when checking that an argument to a method is valid. NullPointerException is supposed to be used whenever an object being "used" when it is null.

I hope that helps put the two in perspective.

于 2008-08-16T18:13:20.263 に答える
-1

IllegalArgumentException をスローする必要があります。これにより、プログラマーが何か無効なことを行ったことが明らかになります。開発者は、VM によって NPE がスローされるのを目にすることに慣れているため、プログラマーは自分のエラーにすぐに気付かず、ランダムに見回したり、さらに悪いことに、コードが「バグ」であると非難したりします。

于 2008-09-09T04:13:05.290 に答える
-1

この場合、IllegalArgumentException は、API を使用しているユーザーに、「 は null であってはならない」という明確な情報を伝えます。他のフォーラム ユーザーが指摘したように、必要に応じて、API を使用してユーザーに正しい情報を伝える限り、NPE を使用できます。

GaryF と tweakt は、NPE の使用を推奨する "Effective Java" (私が誓う) の参照を削除しました。また、他の優れた API がどのように構築されているかを調べることは、API の構築方法を確認するための最良の方法です。

もう 1 つの良い例は、Spring API です。たとえば、org.springframework.beans.BeanUtils.instantiateClass(Constructor ctor, Object[] args) には Assert.notNull(ctor, "Constructor must not be null") 行があります。org.springframework.util.Assert.notNull(Object object, String message) メソッドは、渡された引数 (オブジェクト) が null かどうかを確認し、null の場合は新しい IllegalArgumentException(message) をスローし、それが組織でキャッチされます。 springframework.beans.BeanUtils.instantiateClass(...) メソッド。

于 2008-10-29T16:20:26.617 に答える
-1

それが「セッター」である場合、または後で使用するメンバーを取得している場合は、IllegalArgumentException を使用する傾向があります。

メソッドで今すぐ使用 (逆参照) するものである場合は、積極的に NullPointerException をスローします。有益なメッセージを提供できるので、ランタイムに任せるよりもこれが好きです (ランタイムもこれを行うことができるようですが、それは別の日の暴言です)。

メソッドをオーバーライドする場合は、オーバーライドされたメソッドが使用するものは何でも使用します。

于 2008-08-28T18:03:19.793 に答える
-5

NPEをスローすることを選択し、メソッドで引数を使用している場合、nullを明示的にチェックすることは冗長でコストがかかる可能性があります。VMはすでにそれを行っていると思います。

于 2008-08-11T13:20:39.560 に答える