回答:
参照変数(つまり、オブジェクト)を宣言すると、実際にはオブジェクトへのポインターが作成されます。プリミティブ型の変数を宣言する次のコードについて考えてみますint。
int x;
x = 10;
この例では、変数xはでありint、Javaによって変数が初期化さ0れます。102行目にの値を割り当てると、の値が10によって参照されるメモリ位置に書き込まれxます。
しかし、参照型を宣言しようとすると、別のことが起こります。次のコードを見てください。
Integer num;
num = new Integer(10);
1行目はという変数を宣言していますがnum、実際にはまだプリミティブ値が含まれていません。代わりに、ポインターが含まれています(型がInteger参照型であるため)。何を指し示すかまだ言っていないので、Javaはに設定しますnull。これは、「私は何も指していない」ことを意味します。
2行目では、newキーワードを使用してタイプのオブジェクトをインスタンス化(または作成)Integerし、ポインター変数numをそのIntegerオブジェクトに割り当てます。
これNullPointerExceptionは、変数を宣言したが、オブジェクトを作成せず、変数の内容を使用しようとする前に変数に割り当てた場合に発生します(逆参照と呼ばれます)。つまり、実際には存在しないものを指しています。
.メソッドまたはフィールドへのアクセスに使用したり[、配列にインデックスを付けたりするときに、通常、逆参照が発生します。
numオブジェクトを作成する前に逆参照しようとすると、を取得しNullPointerExceptionます。最も些細なケースでは、コンパイラーが問題をキャッチして、そのことを知らせますがnum may not have been initialized、オブジェクトを直接作成しないコードを作成する場合もあります。
たとえば、次のようなメソッドがあるとします。
public void doSomething(SomeObject obj) {
//do something to obj
}
その場合、オブジェクトを作成するのではなくobj、doSomething()メソッドが呼び出される前に作成されたと想定します。次のようにメソッドを呼び出すことが可能であることに注意してください。
doSomething(null);
その場合、objですnull。メソッドが渡されたオブジェクトに対して何かを行うことを意図している場合、それはNullPointerExceptionプログラマーエラーであり、プログラマーはデバッグ目的でその情報を必要とするため、をスローすることが適切です。次のように、例外メッセージにオブジェクト変数の名前を含めてください
Objects.requireNonNull(a, "a");
または、メソッドの目的が、渡されたオブジェクトを操作することだけではない場合があり、そのためnullパラメータが許容される場合があります。この場合、nullパラメータを確認し、動作を変える必要があります。ドキュメントでもこれを説明する必要があります。たとえば、次のdoSomething()ように書くことができます。
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
プログラムを途中で終了させる原因となる例外を停止するために、原因を特定するためにどのメソッド/ツールを使用できますか?
findbugsを備えたソナーはNPEを検出できます。 JVMによって引き起こされるnullポインター例外を動的にキャッチすることができます
int a=b。bがの場合、NPEをスローできIntegerます。これがデバッグを混乱させるケースがあります。
NullPointerExceptionコードの問題を回避するための追加の方法は@Nullable、および@NotNullアノテーションを使用することです。次の回答には、これに関する詳細情報があります。この答えは、具体的にはIntelliJ IDEに関するものですが、コメントのApparanetと同様に、他のツールにも適用できます。(ところで、この回答を直接編集することは許可されていません。おそらく著者が追加できるでしょうか?)
NullPointerExceptionsは、オブジェクトを参照しているかのように、メモリ内の場所がない(null)を指す参照を使用しようとしたときに発生する例外です。null参照でメソッドを呼び出すか、null参照のフィールドにアクセスしようとすると、がトリガーされますNullPointerException。これらは最も一般的ですが、他の方法がNullPointerExceptionjavadocページにリストされています。
おそらく、私がを説明するために思いつくことができる最も速いサンプルコードは次のようにNullPointerExceptionなります:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
の最初の行でmainは、Object参照をにobj等しく設定していますnull。これは、参照があることを意味しますが、オブジェクトを指していません。その後、参照をメソッドを呼び出すことにより、それがオブジェクトを指しているかのように扱います。NullPointerException参照が指している場所で実行するコードがないため、これはa になります。
(これは専門的であるが、私はそれが言及クマ思う:A参照ヌルにポイントが無効なメモリ位置に点Aのヌルポインタは文字通り指していないことCポインタと同じではないこと。どこよりも微妙に異なっています、たまたま無効な場所を指している。)
null、このように使用する前とは異なる方法に設定することです。ローカル変数を使用すると、コンパイラーはこのエラーをキャッチしますが、この場合はキャッチしません。多分それはあなたの答えに役立つ追加になるでしょうか?
開始するのに適した場所はJavaDocsです。彼らはこれをカバーしています:
オブジェクトが必要な場合にアプリケーションがnullを使用しようとするとスローされます。これらには以下が含まれます:
- nullオブジェクトのインスタンスメソッドを呼び出す。
- nullオブジェクトのフィールドへのアクセスまたは変更。
- nullの長さを配列のように受け取ります。
- 配列であるかのようにnullのスロットにアクセスまたは変更する。
- Throwable値であるかのようにnullをスローします。
アプリケーションは、このクラスのインスタンスをスローして、nullオブジェクトの他の不正な使用を示す必要があります。
また、でnull参照を使用しようとするとsynchronized、JLSごとにこの例外もスローされます。
SynchronizedStatement: synchronized ( Expression ) Block
- それ以外の場合、式の値がnullの場合、a
NullPointerExceptionがスローされます。
だからあなたはNullPointerException。どのように修正しますか?をスローする簡単な例を見てみましょうNullPointerException:
public class Printer {
private String name;
public void setName(String name) {
this.name = name;
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer();
printer.print();
}
}
null値を特定する
最初のステップは、例外を引き起こしている値を正確に特定することです。このため、デバッグを行う必要があります。スタックトレースの読み方を学ぶことは重要です。これは、例外がスローされた場所を示します。
Exception in thread "main" java.lang.NullPointerException
at Printer.printString(Printer.java:13)
at Printer.print(Printer.java:9)
at Printer.main(Printer.java:19)
ここでは、13行目(printStringメソッド内)で例外がスローされていることがわかります。行を見て、ロギングステートメントを追加するか、デバッガを使用して、どの値がnull かを確認します。これsがnullであることがわかり、そのlengthメソッドを呼び出すと例外がスローされます。s.length()メソッドからが削除されると、プログラムが例外のスローを停止することがわかります。
これらの値の出所を追跡する
次に、この値の出所を確認します。メソッドの呼び出し元をたどることにより、それがメソッドs内で渡され、null printString(name)であることがわかります。print()this.name
これらの値を設定する必要がある場所をトレースする
どこにthis.name設定されていますか?ではsetName(String)方法。さらにデバッグを行うと、このメソッドがまったく呼び出されないことがわかります。メソッドが呼び出された場合は、これらのメソッドが呼び出される順序を確認してください。また、setメソッドは、printメソッドの後に呼び出されません。
これで十分です。を呼び出すprinter.setName()前にに呼び出しを追加してくださいprinter.print()。
変数はデフォルト値を持つことができます(そしてsetNameそれがnullに設定されるのを防ぐことができます):
private String name = "";
printまたはprintStringメソッドのいずれかでnullをチェックできます。次に例を示します。
printString((name == null) ? "" : name);
または、name 常にnull以外の値を持つようにクラスを設計できます。
public class Printer {
private final String name;
public Printer(String name) {
this.name = Objects.requireNonNull(name);
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer("123");
printer.print();
}
}
以下も参照してください。
問題をデバッグしようとしても解決策がない場合は、質問を投稿してさらにヘルプを得ることができますが、これまでに試した内容を必ず含めてください。少なくとも、質問にスタックトレースを含め、コードの重要な行番号をマークします。また、最初にコードを簡略化してみてください(SSCCEを参照)。
NullPointerException(NPE)の原因は何ですか?あなたが知っておくべきこととして、Javaタイプが分かれているプリミティブ型(boolean、intなど)と参照型。Javaの参照型でnullは、Javaの「オブジェクトなし」と言う特別な値を使用できます。
NullPointerExceptionプログラムnullが実際の参照であるかのようにプログラムを使用しようとすると、実行時にA がスローされます。たとえば、次のように記述したとします。
public class Test {
public static void main(String[] args) {
String foo = null;
int length = foo.length(); // HERE
}
}
「HERE」というラベルの付いたステートメントはlength()、null参照でメソッドを実行しようとしますNullPointerException。これにより、がスローされます。
nullをもたらす値を使用する方法はたくさんありますNullPointerException。実際には、あなたがいることを唯一のものができて行うnullNPEを発生させずには、以下のとおりです。
==or !=演算子、またはを使用してテストしinstanceofます。上記のプログラムをコンパイルして実行するとします。
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:4)
$
最初の観察:コンパイルは成功しました!プログラムの問題はコンパイルエラーではありません。それは、実行時エラーが発生しました。(一部のIDEは、プログラムが常に例外をスローすることを警告することがありますが、標準のjavacコンパイラーは例外をスローしません。)
2番目の観察:プログラムを実行すると、「gobbledy-gook」の2行が出力されます。違う!!それはむちゃくちゃじゃない。これはスタックトレースです...そして、時間をかけて注意深く読んだ場合、コード内のエラーを追跡するのに役立つ重要な情報を提供します。
だからそれが言うことを見てみましょう:
Exception in thread "main" java.lang.NullPointerException
スタックトレースの最初の行は、いくつかのことを示しています。
java.lang.NullPointerException。NullPointerExceptionエラーメッセージが表示されることはめったにないため、この点で異常です。2行目は、NPEの診断で最も重要な行です。
at Test.main(Test.java:4)
これはいくつかのことを教えてくれます:
main、Testクラスのメソッドにいたことを示しています。上記のファイルの行数を数えると、4行目は「ここ」のコメントでラベル付けした行です。
より複雑な例では、NPEスタックトレースに多数の行があることに注意してください。しかし、2行目(最初の "at"行)でNPEがどこにスローされたかが確実にわかります1。
つまり、スタックトレースにより、プログラムのどのステートメントがNPEをスローしたかが明確にわかります。
1-まったく正しくない。ネストされた例外と呼ばれるものがあります...
これは難しい部分です。簡単な答えは、スタックトレース、ソースコード、および関連するAPIドキュメントによって提供される証拠に論理的な推論を適用することです。
最初に簡単な例(上記)で説明しましょう。まず、スタックトレースがNPEが発生した場所であると通知した行を確認します。
int length = foo.length(); // HERE
どうすればNPEをスローできますか?
実際、方法は1つしかありません。foo値がの場合にのみ発生しますnull。次に、length()メソッドを実行しようとしますnull... BANG!
しかし、(私はあなたが言うのを聞きます)NPEがlength()メソッド呼び出し内でスローされた場合はどうでしょうか?
まあ、それが起こった場合、スタックトレースは異なって見えます。最初の「at」行は、java.lang.Stringクラスの一部の行で例外がスローされたTest.javaことを示し、4行目は2番目の「at」行になります。
それはどこnullから来たのですか?この場合、それは明白であり、それを修正するために何をする必要があるかは明らかです。(null以外の値をに割り当てますfoo。)
では、少しトリッキーな例を試してみましょう。これには、いくつかの論理的な控除が必要になります。
public class Test {
private static String[] foo = new String[2];
private static int test(String[] bar, int pos) {
return bar[pos].length();
}
public static void main(String[] args) {
int length = test(foo, 1);
}
}
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.test(Test.java:6)
at Test.main(Test.java:10)
$
これで、2つの「アット」ラインができました。最初のものはこの行のためのものです:
return args[pos].length();
そして2番目はこの行用です:
int length = test(foo, 1);
最初の行を見ると、どうすればNPEをスローできますか?2つの方法があります。
barでnull、その後bar[pos]NPEをスローします。bar[pos]がnull次に呼び出さlength()れると、NPEがスローされます。次に、これらのシナリオのどれが実際に何が起こっているのかを説明する必要があります。最初の1つを探索することから始めます。
どこbarから来たの?これはtestメソッド呼び出しのパラメーターであり、どのようtestに呼び出されたかを見ると、foo静的変数からのものであることがわかります。さらに、foonull以外の値に初期化したことがはっきりとわかります。これでこの説明を一時的に却下するには十分です。(理論的には、何か他のものは...に変わる 可能性fooがありnullますが、それはここでは起こりません。)
では、2番目のシナリオはどうでしょうか。さて、私たちはそれを見ることができposている1ことを意味しそうfoo[1]でなければなりませんnull。これは可能ですか?
確かにそうです!そしてそれが問題です。このように初期化すると:
private static String[] foo = new String[2];
に初期化されるString[] 2つの要素をnull持つを割り当てます。その後、我々はの内容を変更していないfooので... foo[1]まだなりますnull。
であるオブジェクトにアクセスしようとしているようですnull。以下の例を考えてみましょう:
TypeA objA;
この時点で、このオブジェクトを宣言しましたが、初期化またはインスタンス化していません。そして、その中の任意のプロパティまたはメソッドにアクセスしようとするときはいつでも、それはスローさ NullPointerExceptionれます。
以下の例も参照してください。
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
オブジェクトが必要な場合にアプリケーションがnullを使用しようとすると、nullポインター例外がスローされます。これらには以下が含まれます:
nullオブジェクトのインスタンスメソッドを呼び出す。nullオブジェクトのフィールドへのアクセスまたは変更。null配列のように長さをとります。null。nullそれはThrowableの値であるかのように。アプリケーションは、このクラスのインスタンスをスローして、nullオブジェクトの他の不正使用を示す必要があります。
リファレンス:http : //docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
nullaをsynchronizedブロックnullのターゲットとして使用する、2)aをa のターゲットとして使用するswitch、およびボックス化解除するnull。
nullポインタは、1ポイントはどこにあるという。ポインタを逆参照するpと、「pに格納されている場所にあるデータをください。ポインタpがにある場合null、格納されている場所pはnowhereです。明らかに、これは実行できないため、をスローしnull pointer exceptionます。
一般に、何かが適切に初期化されていないためです。
NULLはnullJavaのように記述されます。そして、それは大文字と小文字を区別するものです。
それがどのように発生し、それを修正する方法を説明するために、多くの説明がすでに存在していますが、回避するためのベストプラクティスに従う必要もありますNullPointerException sをまったくの。
参照: ベストプラクティスの良いリスト
非常に重要なことですが、final修飾子を上手に利用します。
Javaで該当する場合は常に「最終」修飾子を使用する
概要:
final修飾子を使用して適切な初期化を実施します。@NotNullを使用し、@Nullableif("knownObject".equals(unknownObject)valueOf()オーバーtoString()。StringUtilsメソッドを使用しますStringUtils.isEmpty(null)。@Nullable上記)に基づいて自動nullity分析を提供し、潜在的なエラーについて警告することに言及する価値があります。既存のコード構造に基づいて、そのような注釈を推測して生成することもできます(たとえば、IntelliJがそれを行うことができます)。
if (obj==null)。
Javaでは、すべて(プリミティブ型を除く)はクラスの形式です。
オブジェクトを使用する場合は、2つのフェーズがあります。
例:
Object object;object = new Object();アレイの概念も同じです。
Item item[] = new Item[5];item[0] = new Item();初期化セクションを指定していない場合は、NullPointerException発生します。
nullポインタ例外は、オブジェクトを初期化せずに使用していることを示します。
たとえば、以下はコードで使用する学生クラスです。
public class Student {
private int id;
public int getId() {
return this.id;
}
public setId(int newId) {
this.id = newId;
}
}
以下のコードは、nullポインタ例外を提供します。
public class School {
Student student;
public School() {
try {
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
を使用しstudentているが、以下に示す正しいコードのように初期化するのを忘れたため。
public class School {
Student student;
public School() {
try {
student = new Student();
student.setId(12);
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
Javaあなたが宣言するすべての変数は、実際のオブジェクト(またはプリミティブ)といないオブジェクト自体への「参照」です。
1つのオブジェクトメソッドを実行しようとすると、参照は生きているオブジェクトにそのメソッドの実行を要求します。しかし、参照がNULL(nothing、zero、void、nada)を参照している場合、メソッドが実行される方法はありません。次に、ランタイムはNullPointerExceptionをスローすることでこれを通知します。
参照はnullを「ポイント」しているため、「null->ポインタ」となります。
オブジェクトはVMのメモリ空間に存在し、オブジェクトにアクセスする唯一の方法はthis参照を使用することです。この例を見てみましょう:
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
そしてあなたのコードの別の場所に:
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
これは知っておくべき重要なことです。オブジェクトへの参照がなくなると(上記の例ではreference、otherReference両方がnullを指している場合)、オブジェクトは「到達不能」になります。これを操作する方法がないため、このオブジェクトはガベージコレクションの準備ができており、ある時点で、VMはこのオブジェクトが使用していたメモリを解放し、別のメモリを割り当てます。
NullPointerExceptionオブジェクト配列を宣言し、すぐにその中の要素を逆参照しようとすると、別のa が発生します。
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
この特定のNPEは、比較順序を逆にすれば回避できます。つまり、.equals保証されたnull以外のオブジェクトで使用します。
配列内のすべての要素は、共通の初期値に初期化されます。どのタイプのオブジェクト配列でも、すべての要素がnull。
配列の要素にアクセスまたは逆参照する前に、要素を初期化する必要があります。
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Optionalはnullを返すことでした。キーワードは結構です。それを防ぐ方法を知ることは重要です。これは、1つの一般的な発生とそれを軽減する方法を提供します。