NullPointerExceptionが原因で失敗するコードがあります。オブジェクトが存在しないオブジェクトでメソッドが呼び出されています。
しかし、これにより、これを修正する最良の方法を考えるようになりました。nullポインタ例外のコードを将来的に保証するために、nullに対して常に防御的にコーディングするか、nullの原因を修正してダウンストリームで発生しないようにする必要がありますか。
あなたの考えは何ですか?
NullPointerExceptionが原因で失敗するコードがあります。オブジェクトが存在しないオブジェクトでメソッドが呼び出されています。
しかし、これにより、これを修正する最良の方法を考えるようになりました。nullポインタ例外のコードを将来的に保証するために、nullに対して常に防御的にコーディングするか、nullの原因を修正してダウンストリームで発生しないようにする必要がありますか。
あなたの考えは何ですか?
回答:
nullがメソッドの適切な入力パラメーターである場合、メソッドを修正します。そうでない場合は、呼び出し元を修正します。「合理的」は柔軟な用語なので、次のテストを提案します。メソッドはどのようにヌル入力を渡すべきですか?考えられる答えが複数見つかった場合、nullは妥当な入力ではありません。
Precondition.checkNotNull(...)
。stackoverflow.com/questions/3022319/…–
IllegalArgumentException
nullが指定されたときにメソッドをスローすることもできます。これは、メソッドの呼び出し側に、バグが(メソッド自体ではなく)コードにあることを通知します。
nullを使用しないで、Optionalを使用します
あなたが指摘したように、null
Java での最大の問題の1つは、どこでも、または少なくともすべての参照型に使用できることです。
それが可能かnull
、不可能かを伝えることは不可能です。
Java 8では、はるかに優れたパターンが導入されていますOptional
。
Oracleの例:
String version = "UNKNOWN";
if(computer != null) {
Soundcard soundcard = computer.getSoundcard();
if(soundcard != null) {
USB usb = soundcard.getUSB();
if(usb != null) {
version = usb.getVersion();
}
}
}
これらのそれぞれが成功した値を返す場合と返さない場合は、APIをOptional
sに変更できます。
String name = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
型のオプション性を明示的にエンコードすることにより、インターフェースがより良くなり、コードがよりきれいになります。
Java 8を使用していない場合はcom.google.common.base.Optional
、Google Guavaをご覧ください。
グアバチームによる適切な説明:https : //github.com/google/guava/wiki/UsingAndAvoidingNullExplained
nullの欠点のより一般的な説明、いくつかの言語の例:https : //www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/
@ Nonnull、@ Nullable
Java 8は、これらの注釈を追加して、IDEなどのコードチェックツールが問題を検出できるようにします。それらの有効性はかなり制限されています。
理にかなっていることを確認する
特に、コードがnull
値を使用して実行できる賢明な方法がない場合は、コードの50%をnullにチェックしないでください。
一方、null
使用できて何か意味がある場合は、必ず使用してください。
最終的に、明らかにnull
Javaから削除することはできません。Optional
可能な限り抽象化を代用し、null
それについて合理的なことができる他の時間をチェックすることを強くお勧めします。
NullPointerException
?A NullPointerException
は、Javaでインスタンスメソッドを呼び出すたびに文字通り発生 します。あなたは持っているでしょうthrows NullPointerException
これまでにほぼすべての単一の方法で。
これを処理するには複数の方法がありますが、コードをペッパーで処理するのif (obj != null) {}
は理想的ではありません。面倒であり、メンテナンスサイクルの後半でコードを読み取るときにノイズが追加され、このボイラープレートラッピングを忘れやすいため、エラーが発生しやすくなります。
コードを静かに実行し続けるか失敗させるかによって異なります。あるnull
エラーまたは予想される状態が。
nullとは
すべての定義とケースで、Nullはデータの絶対的な不足を表します。データベースのヌルは、その列の値がないことを表します。理論的には、null はString
emptyと同じではなく、null はZEROと同じものではありません。実際には「依存する」。Empty は、ビジネスロジックに依存するため、Stringクラスの適切な実装を作成できます。String
int
String
Null Object
Integer
代替手段は次のとおりです。
Null Object
パターン。null
状態を表すオブジェクトのインスタンスを作成し、その型へのすべての参照をNull
実装への参照で初期化します。また、これは可能性が他のオブジェクトへの参照をたくさん持っていないシンプルな値型のオブジェクトのために有用であるnull
とことが期待されnull
、有効な状態とします。
アスペクト指向ツールを使用してNull Checker
、パラメーターがnullにならないようにアスペクトを備えたメソッドを作成します。これはnull
、エラーが発生した場合に使用します。
使用するのassert()
はif (obj != null){}
ノイズよりも少ないが、ノイズは少ない。
Contracts For Javaなどの契約施行ツールを使用します。AspectJのようなものと同じユースケースですが、より新しいものであり、外部構成ファイルの代わりに注釈を使用します。アスペクトとアサートの両方の作品のベスト。
1は、null
アップストリームコンシューマーがすべてのnullチェックボイラープレートコードを処理する必要がないように、着信データが既知であり、デフォルト値に置き換える必要がある場合に理想的なソリューションです。既知のデフォルト値に対するチェックも、より表現力豊かになります。
2、3、および4はNullPointerException
、より有益なものに置き換えるための便利な代替例外ジェネレーターであり、常に改善されています。
最終的には
null
Javaのほとんどすべての場合、論理エラーです。あなたはいつもの根本原因を排除するよう努力するべきですNullPointerExceptions
。null
条件をビジネスロジックとして使用しないように努力する必要があります。if (x == null) { i = someDefault; }
そのデフォルトのオブジェクトインスタンスに初期割り当てを行うだけです。
null == null
、(でもPHPで)が、データベース内null != null
のデータベースにそれが表しているため、未知の値ではなく、「何を」。2つの未知数は必ずしも等しいとは限りませんが、2つの何も等しくありません。
nullチェックを追加すると、テストに問題が生じる可能性があります。この素晴らしい講義をご覧ください...
Google Tech talksの講義をご覧ください:「The Clean Code Talks-Do n't Look For Things!」彼は24分頃にそれについて話します
http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E
妄想プログラミングでは、あらゆる場所にヌルチェックを追加します。最初は良いアイデアのように見えますが、テストの観点からは、nullチェックタイプのテストを扱いにくくしています。
また、次のようなオブジェクトの存在の前提条件を作成する場合
class House(Door door){
.. null check here and throw exception if Door is NULL
this.door = door
}
例外をスローするため、Houseを作成できません。テストケースがドア以外の何かをテストするためのモックオブジェクトを作成していると仮定してください。ドアが必要なため、これはできません。
モック作成地獄で苦しんでいる人は、この種の迷惑をよく知っています。
要約すると、テストスイートは、ドア、家、屋根など、それについて妄想することなくテストできるほど堅牢でなければなりません。Seroiusly、テストの特定のオブジェクトにヌルチェックテストを追加するのはどれほど難しいですか:)
動作することを証明するいくつかのテストがあるため、動作するアプリケーションを常に優先する必要があります。
tl; dr-予期しないnull
s をチェックするのは良いことですが、アプリケーションがそれらを良くしようとするのは悪いことです。
詳細
明らかnull
に、メソッドへの有効な入力または出力である状況とそうでない状況があります。
ルール#1:
null
パラメーターを許可するかnull
値を返すメソッドのjavadocは、これを明確に文書化し、その意味を説明する必要がありますnull
。
ルール#2:
APIメソッド
null
は、正当な理由がない限り、受け入れまたは戻りとして指定しないでください。
法の「契約」の明確な仕様を考えると向かい合っnull
sが、プログラミングエラー渡したり返すためにnull
どこがいけません。
ルール#3:
アプリケーションは、「良い」プログラミングエラーを作ろうとしてはなりません。
null
あるべきではないメソッドをメソッドが検出した場合、他のメソッドに変換して問題を解決しようとするべきではありません。それはプログラマから問題を隠すだけです。代わりに、NPEの発生を許可し、プログラマーが根本原因を特定して修正できるように障害を発生させる必要があります。うまくいけば、テスト中に失敗に気付くでしょう。そうでなければ、それはあなたのテスト方法論について何かを言います。
ルール#4:
可能であれば、プログラミングエラーを早期に検出するコードを記述してください。
コードに多くのNPEが発生するバグがある場合、最も難しいのはnull
値がどこから来たのかを把握することです。診断を容易にする1つの方法は、コードがnull
できるだけ早く検出されるようにコードを記述することです。多くの場合、これは他のチェックと組み合わせて実行できます。例えば
public setName(String name) {
// This also detects `null` as an (intended) side-effect
if (name.length() == 0) {
throw new IllegalArgumentException("empty name");
}
}
(明らかに、ルール3と4を現実に合わせる必要がある場合があります。たとえば(ルール3)、ある種のアプリケーションは、おそらくプログラミングエラーを検出した後に続行しようとする必要があります。パフォーマンスへの影響。)
防御的な方法に修正することをお勧めします。例えば:
String go(String s){
return s.toString();
}
これに沿ったものになるはずです:
String go(String s){
if(s == null){
return "";
}
return s.toString();
}
これは絶対に取るに足らないことであると思いますが、呼び出し側がオブジェクトに、nullが渡されないデフォルトのオブジェクトを与えることを期待している場合。
new String()
、まったく使用しないでください。
null
sをサイレントに修正することは、NPEをスローすることよりも悪い最悪のオプションです。
これまでのところ、nullに関する次の一般的なルールは、私を大いに助けてくれました。
データがコントロール外から来た場合、nullを体系的にチェックし、適切に動作します。これは、関数に意味のある例外をスローすることを意味します(チェック済みまたは未チェック、例外の名前が正確に何が起こっているかを確認するだけです)。しかし、システムに潜在的な驚きをもたらす可能性のある値を決して緩めないでください。
Nullがデータモデルの適切な値のドメイン内にある場合は、適切に処理します。
値を返すときは、可能な限りnullを返さないようにしてください。常に空のリスト、空の文字列、Null Objectパターンを好みます。これが特定のユースケースのデータの可能な限り最良の表現である場合、戻り値としてヌルを保持します。
おそらく最も重要なのは...テスト、テスト、そして再びテスト。コードをテストするときは、コードとしてテストしないでください。ナチのサイコパスの支配者としてテストし、そのコードから地獄を拷問するあらゆる種類の方法を想像してみてください。
これは、システムが外部の世界とインターフェイスし、冗長性が豊富な内部の値を厳密に制御するファサードやプロキシーにつながることが多いヌルに関して、偏執的な側面に少しありがちです。ここの外の世界は、私が自分でコーディングしなかったほとんどすべてのものを意味します。実行時間はかかりますが、これまでのところ、コードの「null安全なセクション」を作成して最適化する必要はほとんどありませんでした。私は主にヘルスケアのために長時間稼働するシステムを作成し、最後にしたいことは、他のシステムの他の誰かがその名前がアポストロフィまたはただし耒耨のような文字を含む。
とにかく....私の2セント
関数型言語のOption / Some / Noneパターンを使用することを提案します。私はJavaの専門家ではありませんが、C#プロジェクトでこのパターンの独自の実装を集中的に使用しており、Javaの世界に変換できると確信しています。
このパターンの背後にある考え方は次のとおりです。値が存在しない可能性がある状況(たとえば、idでデータベースから取得する)が論理的に存在する場合、Option [T]型のオブジェクトを提供します。 。クラスNone [T]の値オブジェクトが存在しない場合、値が存在する場合-Some [T]のオブジェクトが返され、値が含まれている場合。
この場合、値が存在しない可能性を処理する必要があります。コードレビューを行うと、不適切な処理の場所を簡単に見つけることができます。C#言語の実装からインスピレーションを得るには、私のbitbucketリポジトリhttps://bitbucket.org/mikegirkin/optionsomenoneを参照してください
null値を返し、それが論理的にエラーと同等である場合(たとえば、ファイルが存在しない、接続できなかったなど)、例外をスローするか、別のエラー処理パターンを使用する必要があります。この背後にある考え方は、値の不在の状況を処理する必要があり、コード内の誤った処理の場所を簡単に見つけることができる場合、解決策になります。
Apache Commonsのlangライブラリは、null値を処理する方法を提供します
クラスObjectUtilsのメソッドdefaultIfNullを使用すると、渡されたオブジェクトがnullの場合にデフォルト値を返すことができます
本当にオプションである場合を除き、オプションとして使用しないでください。多くの場合、定期的にバグのあるコードを作成するためではなく、オプションとして本当にnullを想定している場合を除き、出口は例外として適切に処理されます。
Googleの記事が指摘しているように、問題はその用途があるためnullではありません。問題は、nullをチェックして処理する必要があることです。多くの場合、nullは正常に終了できます。
プログラムのルーチン操作以外の領域で無効な条件(無効なユーザー入力、データベースの問題、ネットワーク障害、ファイルの欠落、データの破損)を表すヌルのケースがいくつかあります。記録するだけの場合。
例外処理には、オプションのようなタイプとは異なり、JVMで異なる操作の優先順位と特権が許可されます。例外の発生の例外的な性質に意味があり、メモリへのハンドラーの優先的な遅延読み込みの早期サポートを含む常にぶらぶらしている必要があります。
nullハンドラーをあちこちに記述する必要はありません。発生する可能性がある場所、信頼できないデータサービスにアクセスする可能性のある場所のみ、これらのほとんどは簡単に抽象化できるいくつかの一般的なパターンに該当するため、本当に必要なのはまれな場合を除き、ハンドラー呼び出し。
したがって、私の答えは、チェックされた例外でラップして処理するか、信頼できないコードを修正できると思います。