NullPointerExceptionとは何ですか?どのように修正しますか?


210

ヌルポインター例外(java.lang.NullPointerException)とは何ですか?

プログラムを途中で終了させる原因となる例外を停止するために、原因を特定するためにどのメソッド/ツールを使用できますか?

回答:


3764

参照変数(つまり、オブジェクト)を宣言すると、実際にはオブジェクトへのポインターが作成されます。プリミティブ型の変数を宣言する次のコードについて考えてみます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
}

その場合、オブジェクトを作成するのではなくobjdoSomething()メソッドが呼び出される前に作成されたと想定します。次のようにメソッドを呼び出すことが可能であることに注意してください。

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ポインター例外を動的にキャッチすることができます


558
「このタイプの例外を回避する最良の方法は、自分でオブジェクトを作成しなかった場合は常にnullをチェックすることです。」呼び出し側がnullを渡したが、nullがメソッドの有効な引数ではない場合、それは呼び出し側の障害であるため、呼び出し側で例外をスローするのは正しいことです。無効な入力を黙って無視し、メソッドで何もしないことは、問題を隠してしまうため、非常に悪いアドバイスです。
Boann、2014

104
この投稿について、オートボクシングを使用すると、プリミティブへの割り当てでもNPEが発生する可能性があることを説明するコメントを追加しますint a=b。bがの場合、NPEをスローできIntegerます。これがデバッグを混乱させるケースがあります。
Simon Fischer 14

58
それは、WebブラウザからWebアプリケーションによってスローされたNPEをキャプチャすることが可能であるような、それは、Webブラウザからの眺めページのソースに表示されます..?
シド

76
はい、オブジェクトのメソッドを呼び出す前、またはオブジェクトが持つ可能性のある変数にアクセスする前に、オブジェクトがnullに等しいかどうかを確認してください。コードを構造化すると、ヌルポインター例外を回避できる場合があります。たとえば、入力文字列を定数文字列でチェックする場合は、次のような定数文字列で開始する必要があります。if( "SomeString" .equals(inputString)){} // inputStringがnullの場合でも、例外はスローされません。したがって、安全を確保するためにできることはたくさんあります。
ローズ

78
NullPointerExceptionコードの問題を回避するための追加の方法は@Nullable、および@NotNullアノテーションを使用することです。次の回答には、これに関する詳細情報があります。この答えは、具体的にはIntelliJ IDEに関するものですが、コメントのApparanetと同様に、他のツールにも適用できます。(ところで、この回答を直接編集することは許可されていません。おそらく著者が追加できるでしょうか?)
Arjan Mels

879

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ポインタと同じではないこと。どこよりも微妙に異なっています、たまたま無効な場所を指している。)


49
私はあなたがそこに書いたすべてを理解しましたが、それは私がしばらくコーディングしていて、「ポインター」と「リファレンス」が何であるか(そして、そのことについてはnullが何であるか)を知っているからです。私がそのような説明に直接飛び込もうとすると、十分な背景がないので、私の生徒たちは私を交差させて見ます。
mmr 2009

33
@mmr:フィードバックをありがとう、有効なポイントを作成します。誰かがどこにいるのか、どのレベルで説明を開始しても安全かをインターネットで実際に判断することは困難です。これをもう一度修正してみます。
リザードを請求する

22
実際にNullPointerExceptionを取得するより一般的な方法は、メンバー変数を明示的に初期化することを忘れてからnullこのように使用する前とは異なる方法に設定することです。ローカル変数を使用すると、コンパイラーはこのエラーをキャッチしますが、この場合はキャッチしません。多分それはあなたの答えに役立つ追加になるでしょうか?
Ilmari Karonen 2014年

6
@EJP私はあなたのポイントは有効だと思うので、答えをより明確にし、「nullへのポイント」と言わないように答えを更新しました。
Steve Powell

5
@StevePowellずっと前に、自分の答えを変えたくないと指摘しました。原作者の意図を尊重してください。
トカゲに請求

696

NullPointerExceptionとは何ですか?

開始するのに適した場所はJavaDocsです。彼らはこれをカバーしています:

オブジェクトが必要な場合にアプリケーションがnullを使用しようとするとスローされます。これらには以下が含まれます:

  • nullオブジェクトのインスタンスメソッドを呼び出す。
  • nullオブジェクトのフィールドへのアクセスまたは変更。
  • nullの長さを配列のように受け取ります。
  • 配列であるかのようにnullのスロットにアクセスまたは変更する。
  • Throwable値であるかのようにnullをスローします。

アプリケーションは、このクラスのインスタンスをスローして、nullオブジェクトの他の不正な使用を示す必要があります。

また、でnull参照を使用しようとするとsynchronizedJLSごとにこの例外もスローされます。

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を参照)。


44
+1スタックトレースを通過することを含む例があるとよい。NPEのデバッグにそれを読むことが重要である理由を示すことが重要です。(そして、エラーに関する質問が投稿されたときに、ほとんど常にスタックトレースを探す理由)
Dennis Meng

16
デバッグについて説明しましたが、どのように機能しますか?このトピックについてしばらく調査してきましたが、何も見つかりません。あなたのような素晴らしい先生がすぐに教えてくれると思います!本当にありがとう!:-)
Ruchir Baronia

15
@RuchirBaroniaデバッガーを使用すると、プログラムを1行ずつステップ実行して、呼び出されるメソッドと変数の変更方法を確認できます。IDEには、これを行うためのいくつかのツールが必要です。たとえば、vogella.com / tutorials / EclipseDebugging / article.htmlを参照してください。
fgb

15
@RuchirBaroniaスタックトレースに表示されているように、NullPointerExceptionの周囲にあるメソッドにブレークポイントを設定し、変数の値を予想どおりにチェックします。あるはずのない変数がnullであることがわかっている場合は、値を変更するコードの周りにブレークポイントを設定できます。値が変更されたときに通知する条件付きブレークポイントもあります。
fgb

6
Stringオブジェクトをデフォルト値として空の文字列に設定することは、不適切なプラクティスと見なされています。
小さな

501

質問:NullPointerException(NPE)の原因は何ですか?

あなたが知っておくべきこととして、Javaタイプが分かれているプリミティブ型booleanintなど)と参照型。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を発生させずには、以下のとおりです。

  • 参照変数に割り当てるか、参照変数から読み取ります。
  • 配列要素に割り当てるか、配列要素から読み取ります(配列参照自体がnullでない場合)。
  • パラメータとして渡すか、結果として返す、または
  • ==or !=演算子、またはを使用してテストしinstanceofます。

質問:NPEスタックトレースを読み取るにはどうすればよいですか?

上記のプログラムをコンパイルして実行するとします。

$ 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スレッドの名前を示します。このスレッドのような1つのスレッドを持つ単純なプログラムの場合、それは「メイン」になります。次へ移りましょう ...
  • スローされた例外の完全な名前がわかります。すなわちjava.lang.NullPointerException
  • 例外に関連するエラーメッセージがある場合は、例外名の後に出力されます。NullPointerExceptionエラーメッセージが表示されることはめったにないため、この点で異常です。

2行目は、NPEの診断で最も重要な行です。

at Test.main(Test.java:4)

これはいくつかのことを教えてくれます:

  • 「at Test.main」はmainTestクラスのメソッドにいたことを示しています。
  • "Test.java:4"はクラスのソースファイル名を示し、これが発生したステートメントがファイルの4行目にあることを示しています。

上記のファイルの行数を数えると、4行目は「ここ」のコメントでラベル付けした行です。

より複雑な例では、NPEスタックトレースに多数の行があることに注意してください。しかし、2行目(最初の "at"行)でNPEがどこにスローされたかが確実にわかります1

つまり、スタックトレースにより、プログラムのどのステートメントがNPEをスローしたかが明確にわかります。

1-まったく正しくない。ネストされた例外と呼ばれるものがあります...

質問:コードでNPE例外の原因を追跡するにはどうすればよいですか?

これは難しい部分です。簡単な答えは、スタックトレース、ソースコード、および関連する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つの方法があります。

  • 値が場合barnull、その後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


425

であるオブジェクトにアクセスしようとしているようですnull。以下の例を考えてみましょう:

TypeA objA;

この時点で、このオブジェクトを宣言しましたが、初期化またはインスタンス化していません。そして、その中の任意のプロパティまたはメソッドにアクセスしようとするときはいつでも、それはスローさ NullPointerExceptionれます。

以下の例も参照してください。

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

1
System.out.println(a.length());を指定すると、// NullPointerExceptionがスローされます。これをスキップするには、try catchブロックで処理できます。ありがとう
ビジャヤヴァルマランケ

359

オブジェクトが必要な場合にアプリケーションがnullを使用しようとすると、nullポインター例外がスローされます。これらには以下が含まれます:

  1. nullオブジェクトのインスタンスメソッドを呼び出す。
  2. nullオブジェクトのフィールドへのアクセスまたは変更。
  3. null配列のように長さをとります。
  4. のようにのスロットにアクセスまたは変更しますnull
  5. 投げ nullそれはThrowableの値であるかのように。

アプリケーションは、このクラスのインスタンスをスローして、nullオブジェクトの他の不正使用を示す必要があります。

リファレンス:http : //docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html


12
シンプルに保つ、私はこの答えが好き、正しいと思う場合はこれを追加-オブジェクトの初期化されていない属性へのアクセス
Emiliano

5
@Emiliano-初期化された属性にアクセスするだけではNPEは発生しません。NPEの原因となるのは、初期化されていない属性値で>> do <<することです。
スティーブンC

1
さらに多くのケースが必要な場合:1)nullaをsynchronizedブロックnullのターゲットとして使用する、2)aをa のターゲットとして使用するswitch、およびボックス化解除するnull
スティーブンC

333

nullポインタは、1ポイントはどこにあるという。ポインタを逆参照するpと、「pに格納されている場所にあるデータをください。ポインタpがにある場合null、格納されている場所pnowhereです。明らかに、これは実行できないため、をスローしnull pointer exceptionます。

一般に、何かが適切に初期化されていないためです。


2
データベースを作成していますか?-> NULLnullJavaのように記述されます。そして、それは大文字と小文字を区別するものです。
bvdb 2018

3
「NULLポインターはどこも指し示していない」とは思いません。nullポインターはどこも指しませんが、null値を指します。
TheRealChx101 2018

2
@ TheRealChx101 nullポインターとnull値へのポインターは異なるものです-nullポインターはnull値を指しません。ポインターへのポインターがあるとします。ポインターAはポインターBを指し、ポインターBはヌルです。この場合、ポインターAはNULL値を指し、ポインターBはNULLポインターです。
MrZebra、

321

それがどのように発生し、それを修正する方法を説明するために、多くの説明がすでに存在していますが、回避するためのベストプラクティスに従う必要もありますNullPointerException sをまったくの。

参照: ベストプラクティスの良いリスト

非常に重要なことですが、final修飾子を上手に利用します。 Javaで該当する場合は常に「最終」修飾子を使用する

概要:

  1. final修飾子を使用して適切な初期化を実施します。
  2. メソッドでnullを返さないようにします。たとえば、該当する場合は空のコレクションを返します。
  3. 注釈@NotNullを使用し、@Nullable
  4. 高速に失敗し、アサートを使用して、nullオブジェクトをnullにしてはいけない場合に、アプリケーション全体に伝播しないようにします。
  5. 最初に、既知のオブジェクトと等しいを使用します。 if("knownObject".equals(unknownObject)
  6. 優先valueOf()オーバーtoString()
  7. nullセーフStringUtilsメソッドを使用しますStringUtils.isEmpty(null)
  8. メソッドの戻り値としてJava 8 Optionalを使用します。Optionalクラスは、null参照の代わりにオプション値を表すソリューションを提供します。

4
j2eeプロジェクトでは、Nullpointer例外が非常に一般的です。場合によっては、変数がnull値を参照することがあります。そのため、変数の初期化を適切に確認する必要があります。また、条件ステートメントでは、フラグまたは参照にnullが含まれているかどうかなどを常に確認する必要があります。-if(flag! = 0){フラグを使用するurコード}
Amaresh Pattanayak '17

14
一部のIDE(例:Eclipse)は、カスタマイズ可能な注釈(例:@Nullable上記)に基づいて自動nullity分析を提供し、潜在的なエラーについて警告することに言及する価値があります。既存のコード構造に基づいて、そのような注釈を推測して生成することもできます(たとえば、IntelliJがそれを行うことができます)。
Jan Chimiak 2016年

4
最初にすべきことは、null許容オブジェクトを使用する前に、それがnullかどうかを確認し、if (obj==null)
Lakmal Vithanage 2017

4
IMO、契約では、コード内の「if(obj == null)」の量を減らして改善するために、可能な場合はメソッドでnullオブジェクトを返さないようにし、null入力パラメーターが許可されていない場合はアノテーションを使用することをお勧めしますコードの可読性。
LG

4
これを読んで、これらの「ベストプラクティス」を真実として受け入れる前に:satisfice.com/blog/archives/27
Stephen C

316

Javaでは、すべて(プリミティブ型を除く)はクラスの形式です。

オブジェクトを使用する場合は、2つのフェーズがあります。

  1. 宣言する
  2. 初期化

例:

  • 宣言: Object object;
  • 初期化: object = new Object();

アレイの概念も同じです。

  • 宣言: Item item[] = new Item[5];
  • 初期化: item[0] = new Item();

初期化セクションを指定していない場合は、NullPointerException発生します。


3
インスタンスのメソッドを呼び出すと、NullPointerExceptionが発生することがよくあります。たとえば、参照を宣言したが、インスタンスをポイントしない場合、そのメソッドを呼び出すと、NullPointerExceptionが発生します。例:YourClass ref = null; //またはref = anotherRef; //しかし、anotherRefはインスタンスref.someMethod();をポイントしていません。// NullPointerExceptionをスローします。通常、この方法で修正します。メソッドが呼び出される前に、参照がnullかどうかを判断します。例:if(yourRef!= null){yourRef.someMethod(); }
sunhang 2017

2
または、次のような例外キャプチャを使用します。try{yourRef.someMethod(); } catch(NullPointerException e){// TODO}
sunhang


315

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");
        }
    }
}

7
これは良い例ですが、他のすべての回答ではまだカバーされていない質問に何が追加されるのでしょうか。
Mysticial

13
ここで「初期化されていない」という言葉を使用することは単に不適切です。表示した例は実際には「初期化」されており、nullで初期化されています。初期化されていない変数の場合、コンパイラーは文句を言うでしょう。
Adrian Shum 2013

2
NPE 、初期化されていないフィールドを使用していることを示す場合があります。それはあなたが他のことをしていることの指標かもしれません。このように単一の原因に単純化し過ぎても、誰かがNPEの問題を解決するのに役立ちません...実際の原因がこれ以外の場合。
スティーブンC

309

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...

これは知っておくべき重要なことです。オブジェクトへの参照がなくなると(上記の例ではreferenceotherReference両方がnullを指している場合)、オブジェクトは「到達不能」になります。これを操作する方法がないため、このオブジェクトはガベージコレクションの準備ができており、ある時点で、VMはこのオブジェクトが使用していたメモリを解放し、別のメモリを割り当てます。


280

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));
}

インスタンスレベル(クラスレベルではない)で初期化されていないオブジェクトを操作すると、NullPointerExceptionが発生します。操作はインスタンス固有である必要があります。操作がクラスレベルである場合、初期化されていないオブジェクトで静的メソッドを呼び出すと、NullPointerException例外はスローされません。プリミティブラッパークラスオブジェクトでもNullPointerExceptionがスローされます。
Shailendra Singh

1. NullPointerExceptionはRuntimeExceptionです。つまり、プログラムの実行時に表示され、コンパイル時には表示されません。:(しかし、ほとんどのIDEはこれを発見するのに役立ちます。2.割り当てステートメントでのキーワード「null」の使用を最小限に抑えます。:) 参照URL:
tomj0101

@ tomj0101なぜそのコメントをしたのか完全にわかりません...しかし、2つ目のポイントとして、以前のパターンOptionalはnullを返すことでした。キーワードは結構です。それを防ぐ方法を知ることは重要です。これは、1つの一般的な発生とそれを軽減する方法を提供します。

NullPointerExceptionはランタイム例外であり、キャッチすることはお勧めしませんが、回避することをお勧めします。
聖武天皇

2
@翔:どの時点でそれを捕らえるべきだと提案するのですか?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.