質問

Nullポインター例外( java.lang.NullPointerException )とは何ですか?また、それらの原因は何ですか?

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

役に立ちましたか?

解決

参照変数(つまり、オブジェクト)を宣言すると、実際にはオブジェクトへのポインターが作成されます。プリミティブ型 int の変数を宣言する次のコードを検討してください。

int x;
x = 10;

この例では、変数 x int であり、Javaはそれを 0 に初期化します。 2行目に 10 の値を割り当てると、 10 の値が x で参照されるメモリ位置に書き込まれます。

しかし、参照 type を宣言しようとすると、何か違うことが起こります。次のコードを取得します。

Integer num;
num = new Integer(10);

最初の行は num という名前の変数を宣言していますが、実際にはまだプリミティブ値が含まれていません。代わりに、ポインターが含まれています(型は参照型である Integer であるため)。あなたはまだ何を指しているのかまだ言っていないので、Javaはそれを null に設定します。これは" 私は nothing "を指しています。

2行目では、 new キーワードを使用して、タイプ Integer およびポインター変数 num のオブジェクトをインスタンス化(または作成)します。 Integer オブジェクトに割り当てられます。

NullPointerException は、変数を宣言したがオブジェクトを作成しなかった場合に発生します。したがって、実際には存在しないものを指していることになります。

オブジェクトを作成する前に num を逆参照しようとすると、 NullPointerException が発生します。最も些細なケースでは、コンパイラは問題をキャッチし、" numが初期化されていない可能性がある、quot;ただし、オブジェクトを直接作成しないコードを記述する場合があります。

たとえば、次のようなメソッドがあります:

public void doSomething(SomeObject obj) {
   //do something to obj
}

この場合、オブジェクト obj を作成するのではなく、 doSomething()メソッドが呼び出される前にオブジェクトが作成されたと想定します。次のようにメソッドを呼び出すことができます:

doSomething(null);

この場合、 obj null です。メソッドが渡されたオブジェクトに対して何かを行うことを意図している場合、 NullPointerException をスローするのが適切です。これはプログラマーのエラーであり、プログラマーはデバッグのためにその情報を必要とするからです。

別の方法として、メソッドの目的が、渡されたオブジェクトを操作することだけではない場合があります。そのため、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
    }
}

最後に、例外を特定する方法&スタックトレースを使用する原因

他のヒント

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 になります。

(これは技術的ですが、言及する必要があると思います:nullを指す参照は、無効なメモリの場所を指すCポインターと同じではありません。nullポインターは、文字通りどこでもを指していません、これは無効な場所を指すのとは微妙に異なります。)

NullPointerExceptionとは何ですか?

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

  

アプリケーションがnullを使用しようとしたときにスローされます。   オブジェクトが必要です。これらは次のとおりです。

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

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

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

SynchronizedStatement:
    synchronized ( Expression ) Block
     
      
  • それ以外の場合、Expressionの値がnullの場合、 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()がメソッドから削除されると、プログラムが例外のスローを停止することがわかります。

これらの値の出所を追跡

次に、この値の出所を確認します。メソッドの呼び出し元をたどると、 print()メソッドの printString(name) s が渡され、< code> this.name はnullです。

これらの値を設定する場所を追跡

this.name はどこに設定されますか? setName(String)メソッド内。さらにデバッグすると、このメソッドはまったく呼び出されないことがわかります。メソッドが呼び出された場合、これらのメソッドが呼び出される順序を確認し、setメソッドはprintメソッドの 後に呼び出されません。

これは解決策を提供するのに十分です: printer.print()を呼び出す前に printer.setName()への呼び出しを追加します。

その他の修正

変数にはデフォルト値を指定できます(そして 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();
    }
}

関連項目:

まだ問題が見つかりません

問題をデバッグしようとしても解決策がない場合は、質問を投稿して詳細なヘルプを求めることができますが、これまでに試したことを必ず含めてください。少なくとも、質問にスタックトレースを含め、コードに重要な行番号をマークしてください。また、単純化してみてください

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

ご存じのとおり、Java型はプリミティブ型 boolean int など)と参照型に分かれています。 Javaの参照型を使用すると、特別な値 null を使用できます。これは、Javaで「オブジェクトなし」と言う方法です。

実際の参照であるかのようにプログラムが null を使用しようとすると、実行時に NullPointerException がスローされます。たとえば、次のように記述した場合:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

&quot; HERE&quot;とラベル付けされたステートメント null 参照で length()メソッドを実行しようとすると、 NullPointerException がスローされます。

nullPointerException が発生する null 値を使用する方法は多数あります。実際、NPEを発生させずに null できることは次のとおりです。

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

質問:NPEスタックトレースの読み方

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

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

最初の観察:コンパイルが成功しました!プログラムの問題はコンパイルエラーではありません。これは runtime エラーです。 (一部の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)

これは多くのことを教えてくれます:

  • &quot; at Test.main&quot; Test クラスの main メソッドにいたと言います。
  • &quot; Test.java:4&quot;クラスのソースファイル名を提供し、これが発生したステートメントがファイルの4行目にあることを示します。

上記のファイル内の行を数える場合、4行目は「HERE」というラベルが付いた行です。コメント。

より複雑な例では、NPEスタックトレースに多くの行があることに注意してください。ただし、2行目(最初の&quot; at&quot;行)でNPEがスローされた場所を確実に確認できます 1

要するに、スタックトレースは、プログラムのどのステートメントがNPEをスローしたかを明確に示します。

1-まったくそうではありません。ネストされた例外と呼ばれるものがあります...

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

これは難しい部分です。簡単な答えは、スタックトレース、ソースコード、および関連するAPIドキュメントによって提供される証拠に論理的推論を適用することです。

null のオブジェクトにアクセスしようとしているようです。以下の例を検討してください:

TypeA objA;

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

以下の例を参照してください:

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

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

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

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

参照: http://docs.oracle。 com / javase / 8 / docs / api / java / lang / NullPointerException.html

null ポインターは、どこにも指し示していないポインターです。ポインター p を逆参照すると、「「p」に保存されている場所にあるデータを教えてください」と言います。 p null ポインターである場合、 p に保存されている場所は nowhere であり、&quot; giveと言います場所 'nowhere'&quot;のデータを取得します。明らかに、これができないので、 null pointer exception をスローします。

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

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

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

非常に重要なのは、 final 修飾子を適切に使用することです。 &quot; final&quot;の使用Javaで適用可能な場合は常に修飾子

概要:

  1. final 修飾子を使用して、適切な初期化を強制します。
  2. 該当する場合に空のコレクションを返すなど、メソッドでnullを返すことを避けます。
  3. アノテーション @NotNull および @Nullable
  4. を使用する
  5. 高速で失敗し、アサートを使用して、nullであってはならないアプリケーション全体へのnullオブジェクトの伝播を回避します。
  6. 既知のオブジェクトで最初にequalsを使用: if(&quot; knownObject&quot; .equals(unknownObject)
  7. toString()よりも valueOf()を優先します。
  8. ヌルセーフな StringUtils メソッドを使用 StringUtils.isEmpty(null)

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では、すべて(プリミティブ型を除く)はクラスの形式です。

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

  1. 宣言
  2. 初期化

例:

  • 宣言:オブジェクトオブジェクト;
  • 初期化: object = new Object();

配列の概念と同じ:

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

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

Java で宣言するすべての変数は、実際には&quot; references&quot;です。オブジェクト自体ではなく、オブジェクト(またはプリミティブ)に。

1つのオブジェクトメソッドを実行しようとすると、参照は生きているオブジェクトにそのメソッドの実行を要求します。しかし、参照がNULL(nothing、zero、void、nada)を参照している場合、メソッドを実行する方法はありません。その後、ランタイムはNullPointerExceptionをスローしてこれを知らせます。

参照は「ポインティング」ですnullに、したがって&quot; Null-&gt;ポインタ&quot;。

オブジェクトは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 の別の発生は、オブジェクト配列を宣言し、すぐにその内部の要素を間接参照しようとしたときに発生します。

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

比較の順序を逆にすると、この特定のNPEを回避できます。つまり、保証されたnull以外のオブジェクトで .equals を使用します。

配列内のすべての要素共通の初期値に初期化されます;どのタイプのオブジェクト配列でも、すべての要素が 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));
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top