プロパティの単純なセッターメソッドnull
があり、この特定のプロパティには適していません。私は常にこの状況で引き裂かれました:IllegalArgumentException
、またはをスローする必要がありNullPointerException
ますか?javadocsからは、どちらも適切と思われます。何らかの理解された基準はありますか?それとも、これはあなたが好きなことをすべきものの1つにすぎず、両方とも本当に正しいのですか?
プロパティの単純なセッターメソッドnull
があり、この特定のプロパティには適していません。私は常にこの状況で引き裂かれました:IllegalArgumentException
、またはをスローする必要がありNullPointerException
ますか?javadocsからは、どちらも適切と思われます。何らかの理解された基準はありますか?それとも、これはあなたが好きなことをすべきものの1つにすぎず、両方とも本当に正しいのですか?
回答:
許可された値にIllegalArgumentException
なりたくない場合はが呼び出されているようで、であることが判明した変数を使用しようとした場合にがスローされます。null
NullPointerException
null
IllegalArgumentException
はJavaのObjects.requireNonNull(T)およびGuavaのPreconditions.checkNotNull(T)と矛盾しますNullPointerException
。ただし、正しい答えは間違いなく IllegalArgumentException
、ジェイソンコーエンの優れた答えとコメントセクションで説明されています。
次の理由により、(NPE)IllegalArgumentException
ではなく(IAE)を使用する必要がNullPointerException
あります。
まず、NPE JavaDocは、NPEが適切であるケースを明示的にリストしています。それらのすべてがスローされることに注意してくださいランタイムで時にnull
不適切に使用されます。対照的に、IAEのJavaDocは、「メソッドに不正な引数または不適切な引数が渡されたことを示すためにスローされました」と明確にすることはできません。うん、それはあなたです!
次に、スタックトレースにNPEが表示された場合、何を想定していますか。おそらく誰かがを逆参照しましたnull
。IAEが表示されたら、スタックの最上位にあるメソッドの呼び出し元が不正な値で渡されたと想定します。ここでも、後者の仮定は真実であり、前者は誤解を招くものです。
第3に、IAEはパラメーターの検証用に明確に設計されているため、例外のデフォルトの選択としてそれを想定する必要があるので、なぜ代わりにNPEを選択するのですか?確かに異なる動作ではありません-コードの呼び出しがIAEとは別にNPEをキャッチし、結果として何か異なることを実行することを本当に期待していますか?より具体的なエラーメッセージを伝えようとしていますか?ただし、他のすべての不正なパラメータに対して行う必要があるので、例外メッセージテキストでそれを行うことができます。
4番目に、他のすべての正しくないパラメーターデータはIAEになるので、一貫性がないのはなぜですか?なぜ違法なものnull
が特別であり、他のすべてのタイプの違法な引数とは別個の例外に値するのはなぜですか?
最後に、Java APIの一部がこの方法でNPEを使用するという他の回答による引数を受け入れます。ただし、Java APIは例外タイプから命名規則まですべてに一貫性がないので、Java API(お気に入りの部分)を盲目的にコピーするだけでは、これらの他の考慮事項に勝る十分な議論ではないと思います。
Validate.notNull
(commons lang)とPreconditions.checkNotNull
(
checkArgument(arg != null)
、argを返すという便利さはありませんが、プロジェクトのローカルユーティリティ。」 code.google.com/p/guava-libraries/wiki/IdeaGraveyard
標準はをスローすることNullPointerException
です。一般に間違いのない「Effective Java」では、これについてItem 42(初版)、Item 60(第2版)、またはItem 72(第3版)の「標準例外の使用を好む」で簡単に説明しています。
「間違いなく、すべての誤ったメソッド呼び出しは不正な引数または不正な状態に要約されますが、その他の例外は、特定の種類の不正な引数および状態に対して標準的に使用されます。呼び出し側がnull値が禁止されているパラメータにnullを渡す場合、規則により、 IllegalArgumentExceptionではなく、NullPointerExceptionがスローされます。」
IllegalArgumentException
今日までjava.util.Objects.requireNonNull
Java 7 のメソッドに気付いたときまで、私はすべてnullパラメーターをスローすることに賛成でした。そのメソッドを使用する代わりに、
if (param == null) {
throw new IllegalArgumentException("param cannot be null.");
}
できるよ:
Objects.requireNonNull(param);
NullPointerException
渡したパラメータがの場合は、がスローされますnull
。
そのメソッドがまさに真っ最中であるjava.util
ことを考えると、その存在NullPointerException
は、スローが「Javaによる方法」であることをかなり強く示していると考えています。
とにかく決まっていると思います。
もちろん、NullPointerException
何がnullであったのか、なぜnullであってはならないのかというメッセージを提供できるので、ハードデバッグに関する引数は偽です。と同じようにIllegalArgumentException
。
もう1つの利点はNullPointerException
、非常にパフォーマンスが重要なコードでは、nullの明示的なチェック(およびNullPointerException
わかりやすいエラーメッセージ)を省略できNullPointerException
、nullのメソッドを呼び出すときに自動的に取得されることを信頼できることです。パラメータ。メソッドをすばやく呼び出す(つまり、すぐに失敗する)場合、基本的に同じ効果がありますが、開発者にとってユーザーフレンドリーではありません。ほとんどの場合、明示的にチェックし、どのパラメーターがnullであったかを示す有用なメッセージをスローしてスローする方が良いでしょうが、メソッド/コンストラクターの公開されたコントラクトを壊すことなく、パフォーマンスが要求する場合はそれを変更するオプションがあると便利です。
Preconditions.checkNotNull(arg)
もNPEを投げます。
私はJDKライブラリ、特にコレクションと並行処理の設計に従う傾向があります(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");
}
}
何をするにせよ、悪い値が設定されて、他のコードがそれを使用しようとしたときに例外をスローしないようにしてください。これはデバッグの悪夢になります。常に「フェイルファスト」の原則に従う必要があります。
よく提示されたため、Jason Cohenの議論に賛成票を投じました。少しずつ解体しましょう。;-)
NPEのJavaDocは明示的に言う「ヌルオブジェクトの他の違法な使用」。ランタイムでnullが発生しないはずの状況に限定されている場合は、そのようなケースをすべてはるかに簡潔に定義できます。
間違ったことが想定されている場合は役に立ちませんが、カプセル化が適切に適用されていると想定すると、nullが不適切に逆参照されているかどうか、またはメソッドが不適切なnullを検出して例外を発生させたかどうかを気にする必要はありません。
実際、他の無効な引数は、他のあらゆる種類の例外を引き起こす可能性があります。UnknownHostException、FileNotFoundException、さまざまな構文エラー例外、IndexOutOfBoundsException、認証エラーなど。
一般的に、NPEは、従来、フェイルファストの原則に従わないコードに関連付けられてきたため、非常に悪意があると感じています。さらに、JDKがNPEにメッセージ文字列を入力できなかったため、根本的に確立されていない強力な否定的な感情が生まれています。実際、ランタイムの観点から見たNPEとIAEの違いは、厳密にはその名前です。その観点から見ると、名前をより正確に表すほど、発信者により明確に伝えることができます。
それは「聖戦」形式の質問です。言い換えれば、両方の選択肢は良いですが、人々は死を守る好みを持っています。
NullPointerException
スローする必要があります。それは、JDKの用途、およびインタフェースのために必要ですが、それが(ちょうどのような、より具体的だと慣例だIndexOutOfBoundsException
、などなど、)
それがsetter
メソッドでありnull
、それに渡されている場合、をスローする方が理にかなっていると思いますIllegalArgumentException
。NullPointerException
実際にを使用しようとしている場合、Aの方が理にかなっているようですnull
。
あなたがそれを使用しているとあれば、それはですnull
、NullPointer
。それが渡されて、それがであるnull
場合IllegalArgument
。
Apache Commons Langには、ここで説明する多くのことを行うNullArgumentExceptionがあります。それはIllegalArgumentExceptionを拡張し、その唯一のコンストラクターは、nullでないはずの引数の名前を取ります。
NullArgumentExceptionやIllegalArgumentExceptionのようなものをスローすることは例外的な状況をより正確に説明していると私は感じていますが、私の同僚と私は、この件に関するBlochの助言に従うことにしました。
実際、IllegalArgumentExceptionまたはNullPointerExceptionをスローするという質問は、私の控えめな見解では、Javaでの例外処理を完全には理解していない少数派にとっての「聖なる戦争」にすぎません。一般に、ルールは次のように単純です。
すべての種類の引数制約違反をIllegalArgumentExceptionにマッピングする場合には、少なくとも3つの非常に適切な理由があります。
(1)プログラマーは、引数制約違反のすべてのケースがIllegalArgumentExceptionを引き起こすと安全に想定することはできません。これは、標準クラスの大多数が、特定の種類の例外が利用できない場合、ごみ箱としてではなく、この例外を使用するためです。標準ライブラリはほとんどの場合に違反するさまざまなルールに従っており、ほとんどのAPIユーザーもそれらを使用するため、APIで引数制約違反のすべてのケースをIllegalArgumentExceptionにマッピングしようとすると、クラスを使用したプログラマの不満が生じるだけです。
(2)例外をマッピングすると、実際には、単一継承が原因で別の種類の異常が発生します。すべてのJava例外はクラスであるため、単一継承のみをサポートします。したがって、サブクラスはどちらか一方からしか継承できないため、NullPointerExceptionとIllegalArgumentExceptionの両方を実際に示す例外を作成する方法はありません。したがって、引数がnullの場合にIllegalArgumentExceptionをスローすると、プログラムがプログラムで問題を修正しようとするたびに、APIユーザーが問題を区別することが難しくなります。
(3)マッピングは実際にバグマスキングの危険を生み出します。引数制約違反をIllegalArgumentExceptionにマッピングするには、制約された引数を持つすべてのメソッド内で外側のtry-catchをコーディングする必要があります。ただし、このcatchブロックで単にRuntimeExceptionをキャッチすることは問題外です。これは、引数制約違反が原因ではない場合でも、自分の内部で使用されているliberyメソッドによってスローされた文書化されたRuntimeExceptionをIllegalArgumentExceptionにマッピングするリスクがあるためです。したがって、非常に具体的である必要がありますが、その努力によっても、別のAPIの文書化されていないランタイム例外(バグ)を誤ってAPIのIllegalArgumentExceptionにマッピングした場合から保護されません。
一方、標準的な方法では、ルールは単純なままであり、例外の原因はマスクされておらず、特定のままです。メソッドの呼び出し元にとっても、ルールは簡単です。-不正な値を渡したためにドキュメント化されたランタイム例外が発生した場合は、デフォルトで呼び出しを繰り返すか(この特定の例外が必要なため)、コードを修正します。 -一方、指定された引数のセットで発生すると文書化されていないランタイム例外が発生した場合は、メソッドのメーカーにバグレポートを提出して、コードまたはドキュメントのいずれかが修正されていることを確認します。
IllegalArgumentException(String message)を使用してパラメーターを無効に宣言し、可能な限り詳細な情報を提供する場合に受け入れられる慣習...つまり、パラメーターがnullであるのに例外がnullでないことが判明した場合は、次のようにします。このような:
if( variable == null )
throw new IllegalArgumentException("The object 'variable' cannot be null");
「NullPointerException」を暗黙的に使用する理由はほとんどありません。NullPointerExceptionは、null参照でコードを実行しようとすると(toString()のように)、Java仮想マシンによってスローされる例外です。
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つの引数リスト:"", null
およびnull, ImmutableList.of()
。これらの呼び出しのそれぞれが予期しNullPointerException
たものをスローすることをテストします。この実装では、null
リストを渡してもは生成されませんNullPointerException
。ただし、たまたまデフォルトの文字列を使用しているIllegalArgumentException
ため、NullPointerTester
偶然にが生成されます""
。値NullPointerTester
のみNullPointerException
を期待する場合はnull
、バグをキャッチします。それが期待するなら、それはIllegalArgumentException
それを逃します。
一部のコレクションは、ではなくnull
を使用して拒否されると想定しています。たとえば、を含むセットを拒否するセットと比較すると、最初のセットは他のセットを呼び出してキャッチしますが、キャッチしません。(私はの実装を見ています。)NullPointerException
IllegalArgumentException
null
null
containsAll
NullPointerException
IllegalArgumentException
AbstractSet.equals
このように未チェックの例外を使用することはアンチパターンであり、含むコレクションと含まnull
ないコレクションを比較することnull
は、本当に例外を生成する可能性のあるバグである、またはnull
コレクションをまったく配置することが悪い考えであると合理的に主張することができます。それにもかかわらず、そのequals
ような場合に例外をスローする必要があると断言しない限りNullPointerException
、特定の状況では必須であるが他の状況では不要であることを思い出して立ち往生しています。(「「c」の後を除く、NPEの前のIAE ...」)
new TreeSet<>().containsAll(Arrays.asList((Object) null));
が含まれているNPE
ためにスローさList
れますnull
。
主観的な質問として、これはクローズされるべきですが、まだオープンです:
これは、私の以前の勤務先で使用されていた社内ポリシーの一部であり、非常に効果的でした。これはすべてメモリからのものなので、正確な表現を思い出せません。彼らがチェック例外を使用しなかったことは注目に値しますが、それは質問の範囲を超えています。彼らが使用した未チェックの例外は、3つの主要なカテゴリに分類されました。
NullPointerException:意図的にスローしないでください。NPEは、null参照を逆参照するときにVMによってのみスローされます。これらがスローされないことを確実にするために、可能な限りの努力を払う必要があります。@Nullableおよび@NotNullをコード分析ツールと組み合わせて使用して、これらのエラーを見つける必要があります。
IllegalArgumentException:関数への引数が公開ドキュメントに準拠していない場合にスローされるため、渡された引数に関してエラーを識別および説明できます。OPの状況はこのカテゴリに分類されます。
IllegalStateException:関数が呼び出され、その引数が渡されたときに予期しないものであるか、メソッドがメンバーであるオブジェクトの状態と互換性がない場合にスローされます。
たとえば、長さのあるもので使用されるIndexOutOfBoundsExceptionの2つの内部バージョンがありました。IllegalStateExceptionのサブクラスの1つ。インデックスが長さより大きい場合に使用されます。もう1つはIllegalArgumentExceptionのサブクラスで、インデックスが負の場合に使用されます。これは、オブジェクトに項目を追加でき、引数が有効になる一方で、負の数が有効になることはないためです。
私が言ったように、このシステムは非常にうまく機能し、なぜその違いがあるのかを説明するのに誰かを要しました。何が問題だったかがわかると、そのエラーをどこでキャッチして、追加のデバッグ情報を作成できるかがわかります。」
NullPointerException:NPEがスローされないように、Nullケースを処理するかアサーションに入れます。アサーションを入れると、他の2つのタイプの1つになります。可能であれば、アサーションがそもそもあったかのようにデバッグを続行します。
IllegalArgumentException:呼び出しサイトに問題があります。渡される値が別の関数からのものである場合は、誤った値を受け取っている理由を調べてください。引数の1つを渡した場合、期待どおりの結果を返さない関数が見つかるまで、エラーが呼び出しスタックを調べます。
IllegalStateException:関数を正しい順序で呼び出していません。引数の1つを使用している場合は、それらを確認し、問題を説明するIllegalArgumentExceptionをスローします。その後、問題が見つかるまで、スタックに対して頬を伸ばすことができます。
とにかく、彼のポイントは、IllegalArgumentAssertionsをスタックにしかコピーできないということでした。IllegalStateExceptionsまたはNullPointerExceptionsは、関数と関係があるため、スタックに伝達する方法はありません。
一般的には、開発者がすべき決して NullPointerExceptionがスローません。この例外は、コードが値がnullである変数を逆参照しようとしたときにランタイムによってスローされます。したがって、メソッドがnullを明示的に禁止したい場合は、たまたまnull値がNullPointerExceptionを発生させるだけではなく、IllegalArgumentExceptionをスローする必要があります。
他の不正な引数からNull引数を選び出したかったので、IAEからNullArgumentExceptionという例外を導出しました。例外メッセージを読む必要すらなくても、null引数がメソッドに渡されたことを知っているので、メッセージを読むことで、どの引数がnullだったかがわかります。私はまだIAEハンドラーでNullArgumentExceptionをキャッチしますが、ログで違いをすばやく確認できます。
二分法...それらは重なっていませんか?全体の重複しない部分のみが二分法を作成できます。私の考えでは:
throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
NullPointerException
しても何も起こらないため、実際には役に立ちません。役立つ唯一のものはですがIllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException
、多重継承はありません。
上記の2つの例外へのリンクからの定義はIllegalArgumentExceptionです。メソッドに不正または不適切な引数が渡されたことを示すためにスローされます。NullPointerException:オブジェクトが必要な場合にアプリケーションがnullを使用しようとするとスローされます。
ここでの大きな違いは、IllegalArgumentExceptionは、メソッドへの引数が有効であることを確認するときに使用されることになっています。NullPointerExceptionは、オブジェクトがnullのときに「使用」されているオブジェクトを使用することになっています。
それが2つを見通しに役立つことを願っています。
IllegalArgumentExceptionをスローする必要があります。これにより、プログラマーが何か無効なことをしたことが明らかになります。開発者はVMによってNPEがスローされるのを見慣れているため、プログラマーはすぐにエラーを認識せず、ランダムに周りを見回し始めます。
この場合、IllegalArgumentExceptionは、APIを使用して、「nullであってはならない」という明確な情報をユーザーに伝えます。他のフォーラムユーザーが指摘したように、APIを使用して適切な情報をユーザーに伝えたい限り、NPEを使用できます。
GaryFとtweaktは、NPEの使用を推奨する「Effective Java」(私が誓う)のリファレンスを削除しました。そして、他の優れたAPIがどのように構築されるかを見ることが、APIを構築する方法を確認するための最良の方法です。
別の良い例は、Spring APIを調べることです。たとえば、org.springframework.beans.BeanUtils.instantiateClass(Constructor ctor、Object [] args)にはAssert.notNull(ctor、 "Constructor not be null")行があります。org.springframework.util.Assert.notNull(Object object、String message)メソッドは、渡された引数(オブジェクト)がnullであるかどうかを確認し、それがnullの場合は新しいIllegalArgumentException(message)をスローして、それを組織でキャッチします。 springframework.beans.BeanUtils.instantiateClass(...)メソッド。
NPEをスローすることを選択し、メソッドで引数を使用している場合、nullを明示的にチェックすることは冗長でコストがかかる可能性があります。VMはすでにそれを行っていると思います。
NPE
、まだプログラマはで話すIAE
、彼らがしたい場合は、VMの前に。