回答:
参照変数(つまり、オブジェクト)を宣言すると、実際にはオブジェクトへのポインターが作成されます。プリミティブ型の変数を宣言する次のコードについて考えてみますint
。
int x;
x = 10;
この例では、変数x
はでありint
、Javaによって変数が初期化さ0
れます。10
2行目にの値を割り当てると、の値が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と同様に、他のツールにも適用できます。(ところで、この回答を直接編集することは許可されていません。おそらく著者が追加できるでしょうか?)
NullPointerException
sは、オブジェクトを参照しているかのように、メモリ内の場所がない(null)を指す参照を使用しようとしたときに発生する例外です。null参照でメソッドを呼び出すか、null参照のフィールドにアクセスしようとすると、がトリガーされますNullPointerException
。これらは最も一般的ですが、他の方法がNullPointerException
javadocページにリストされています。
おそらく、私がを説明するために思いつくことができる最も速いサンプルコードは次のように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
。実際には、あなたがいることを唯一のものができて行うnull
NPEを発生させずには、以下のとおりです。
==
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
静的変数からのものであることがわかります。さらに、foo
null以外の値に初期化したことがはっきりとわかります。これでこの説明を一時的に却下するには十分です。(理論的には、何か他のものは...に変わる 可能性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
null
aをsynchronized
ブロックnull
のターゲットとして使用する、2)aをa のターゲットとして使用するswitch
、およびボックス化解除するnull
。
null
ポインタは、1ポイントはどこにあるという。ポインタを逆参照するp
と、「pに格納されている場所にあるデータをください。ポインタp
がにある場合null
、格納されている場所p
はnowhere
です。明らかに、これは実行できないため、をスローしnull pointer exception
ます。
一般に、何かが適切に初期化されていないためです。
NULL
はnull
Javaのように記述されます。そして、それは大文字と小文字を区別するものです。
それがどのように発生し、それを修正する方法を説明するために、多くの説明がすでに存在していますが、回避するためのベストプラクティスに従う必要もありますNullPointerException
sをまったくの。
参照: ベストプラクティスの良いリスト
非常に重要なことですが、final
修飾子を上手に利用します。
Javaで該当する場合は常に「最終」修飾子を使用する
概要:
final
修飾子を使用して適切な初期化を実施します。@NotNull
を使用し、@Nullable
if("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つの一般的な発生とそれを軽減する方法を提供します。