Was ist eine NullPointerException und wie behebe ich sie?

210

Was sind Null-Zeiger-Ausnahmen ( java.lang.NullPointerException) und was verursacht sie?

Mit welchen Methoden / Tools kann die Ursache ermittelt werden, damit die Ausnahme das Programm nicht vorzeitig beendet?

Ziggy
quelle

Antworten:

3763

Wenn Sie eine Referenzvariable (dh ein Objekt) deklarieren, erstellen Sie tatsächlich einen Zeiger auf ein Objekt. Betrachten Sie den folgenden Code, in dem Sie eine Variable vom primitiven Typ deklarieren int:

int x;
x = 10;

In diesem Beispiel ist die Variable xeine intund wird von Java 0für Sie initialisiert . Wenn Sie ihm 10in der zweiten Zeile den Wert von zuweisen , wird Ihr Wert von10 in den Speicherort geschrieben, auf den von verwiesen wird x.

Aber, wenn Sie versuchen , einen Verweis zu erklären Art , geschieht etwas anderes. Nehmen Sie den folgenden Code:

Integer num;
num = new Integer(10);

Die erste Zeile deklariert eine Variable mit dem Namen num, enthält jedoch noch keinen primitiven Wert. Stattdessen enthält es einen Zeiger (da der Typ Integerein Referenztyp ist). Da Sie noch nicht gesagt haben, worauf Sie zeigen sollen, setzt Java darauf null, was bedeutet " Ich zeige auf nichts ".

In der zweiten Zeile wird das newSchlüsselwort verwendet, um ein Objekt vom Typ zu instanziieren (oder zu erstellen), Integerund die Zeigervariable numwird diesem IntegerObjekt zugewiesen .

Dies NullPointerExceptiontritt auf, wenn Sie eine Variable deklarieren, aber kein Objekt erstellt und der Variablen zugewiesen haben, bevor Sie versuchen, den Inhalt der Variablen zu verwenden ( Dereferenzierung genannt ). Sie zeigen also auf etwas, das es eigentlich nicht gibt.

Dereferenzierung tritt normalerweise bei der Verwendung auf . auf eine Methode oder ein Feld wird oder[ ein Array indiziert wird.

Wenn Sie versuchen, eine Dereferenzierung numdurchzuführen, bevor Sie das Objekt erstellen, erhalten Sie eine NullPointerException. In den trivialsten Fällen num may not have been initializederkennt der Compiler das Problem und teilt Ihnen mit, dass " ," aber manchmal können Sie Code schreiben, der das Objekt nicht direkt erstellt.

Beispielsweise können Sie eine Methode wie folgt verwenden:

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

In diesem Fall erstellen Sie das Objekt nicht obj, sondern gehen davon aus, dass es vor dem doSomething()Aufruf der Methode erstellt wurde. Beachten Sie, dass die Methode folgendermaßen aufgerufen werden kann:

doSomething(null);

In welchem ​​Fall objist null. Wenn die Methode etwas mit dem übergebenen Objekt tun soll, ist es angebracht, das auszulösen, NullPointerExceptionda es sich um einen Programmiererfehler handelt und der Programmierer diese Informationen zum Debuggen benötigt. Bitte geben Sie den Namen der Objektvariablen in die Ausnahmemeldung ein, z

Objects.requireNonNull(a, "a");

Alternativ kann es Fälle geben, in denen der Zweck des Verfahrens nicht nur darin besteht, das übergebene Objekt zu bearbeiten, und daher kann ein Nullparameter akzeptabel sein. In diesem Fall müssten Sie nach einem Nullparameter suchen und sich anders verhalten. Sie sollten dies auch in der Dokumentation erläutern. Zum Beispiel doSomething()könnte geschrieben werden als:

/**
  * @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
    }
}

Schließlich, So lokalisieren Sie die Ausnahme und Ursache mithilfe der Stapelverfolgung

Mit welchen Methoden / Tools kann die Ursache ermittelt werden, damit die Ausnahme das Programm nicht vorzeitig beendet?

Sonar mit Findbugs kann NPE erkennen. Kann Sonar Nullzeigerausnahmen abfangen, die von JVM Dynamisch verursacht werden?

Vincent Ramdhanie
quelle
558
"Der beste Weg, um diese Art von Ausnahme zu vermeiden, besteht darin, immer nach Null zu suchen, wenn Sie das Objekt nicht selbst erstellt haben." Wenn der Aufrufer null übergibt, aber null kein gültiges Argument für die Methode ist, ist es richtig, die Ausnahme zurück auf den Aufrufer zu werfen, da dies die Schuld des Aufrufers ist. Das stille Ignorieren ungültiger Eingaben und das Nichtstun in der Methode ist ein äußerst schlechter Rat, da das Problem dadurch ausgeblendet wird.
Boann
104
Ich möchte eine Bemerkung zu diesem Beitrag hinzufügen, in der erklärt wird, dass selbst Zuweisungen zu Grundelementen bei Verwendung von Autoboxing NPEs verursachen können: int a=bKann eine NPE auslösen, wenn b eine ist Integer. Es gibt Fälle, in denen das Debuggen verwirrend ist.
Simon Fischer
58
Ist es möglich, NPE zu erfassen, die von einer Webanwendung über den Webbrowser ausgelöst werden? Wie wird es in der Ansichtsseitenquelle des Webbrowsers angezeigt?
Sid
76
Ja, überprüfen Sie, ob das Objekt gleich null ist, bevor Sie eine Methode aufrufen oder versuchen, auf eine Variable zuzugreifen, über die es möglicherweise verfügt. Manchmal kann die Strukturierung Ihres Codes dazu beitragen, eine Nullzeigerausnahme zu vermeiden. Wenn Sie beispielsweise eine Eingabezeichenfolge mit einer konstanten Zeichenfolge überprüfen, sollten Sie mit der konstanten Zeichenfolge wie folgt beginnen: if ("SomeString" .equals (inputString)) {} // Auch wenn inputString null ist, wird keine Ausnahme ausgelöst. Es gibt also eine Reihe von Dingen, die Sie tun können, um sicher zu gehen.
Rose
78
Eine zusätzliche Möglichkeit, NullPointerExceptionProbleme in Ihrem Code zu vermeiden , ist die Verwendung von @Nullableund @NotNullAnmerkungen. Die folgende Antwort enthält weitere Informationen dazu. Obwohl sich diese Antwort speziell auf die IntelliJ-IDE bezieht, gilt sie auch für andere Tools, wie dies aus den Kommentaren hervorgeht. (Übrigens darf ich diese Antwort nicht direkt bearbeiten, vielleicht kann der Autor sie hinzufügen?)
Arjan Mels
879

NullPointerExceptions sind Ausnahmen, die auftreten, wenn Sie versuchen, eine Referenz zu verwenden, die auf keinen Speicherort im Speicher verweist (null), als würde sie auf ein Objekt verweisen. Wenn Sie eine Methode für eine Nullreferenz aufrufen oder versuchen, auf ein Feld einer Nullreferenz zuzugreifen, wird a ausgelöst NullPointerException. Dies sind die häufigsten, aber andere Möglichkeiten sind auf der NullPointerExceptionJavadoc-Seite aufgeführt.

Der wahrscheinlich schnellste Beispielcode, den ich zur Veranschaulichung von a finden könnte, NullPointerExceptionwäre:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

In der ersten Zeile mainsetze ich die ObjectReferenz explizit objauf null. Dies bedeutet, dass ich eine Referenz habe, die jedoch nicht auf ein Objekt zeigt. Danach versuche ich, die Referenz so zu behandeln, als ob sie auf ein Objekt verweist, indem ich eine Methode darauf aufrufe. Dies führt zu aNullPointerException da an der Stelle, auf die die Referenz zeigt, kein Code ausgeführt werden muss.

(Dies ist eine technische Angelegenheit, aber ich denke, sie sollte erwähnt werden: Eine Referenz, die auf Null zeigt, ist nicht dasselbe wie ein C-Zeiger, der auf einen ungültigen Speicherort zeigt. Ein Nullzeiger zeigt buchstäblich nirgendwo hin , was sich geringfügig von unterscheidet auf einen Ort zeigen, der zufällig ungültig ist.)

Bill the Lizard
quelle
49
Ich habe alles verstanden, was Sie dort geschrieben haben, aber nur, weil ich schon eine Weile codiert habe und weiß, was ein "Zeiger" und eine "Referenz" sind (und was null ist). Wenn ich versuche, direkt in solche Erklärungen einzutauchen, sehen mich meine Schüler gekreuzt an, weil es nicht genug Hintergrund gibt.
mmr
33
@mmr: Danke für das Feedback, du machst einen gültigen Punkt. Im Internet ist es schwierig zu beurteilen, wo sich jemand befindet und auf welcher Ebene es sicher ist, eine Erklärung zu beginnen. Ich werde versuchen, dies noch einmal zu überarbeiten.
Bill the Lizard
22
Ein häufiger Weg , um eine Nullpointer in der Praxis bekommen würde zu vergessen explizit eine Membervariable , um etwas zu initialisieren anders als nullzuvor, mit wie diese . Bei lokalen Variablen würde der Compiler diesen Fehler abfangen, in diesem Fall jedoch nicht. Vielleicht wäre das eine nützliche Ergänzung zu Ihrer Antwort?
Ilmari Karonen
6
@EJP Ich denke, Ihre Punkte sind gültig, daher habe ich die Antwort aktualisiert, um klarer zu sein und zu vermeiden, dass "Punkte auf Null" gesagt wird, wo dies der Fall war.
Steve Powell
5
@StevePowell Ich habe vor langer Zeit angegeben, dass sich meine Antwort nicht ändern soll. Bitte respektieren Sie die Absicht des ursprünglichen Autors.
Bill the Lizard
696

Was ist eine NullPointerException?

Ein guter Anfang sind die JavaDocs . Sie haben dies abgedeckt:

Wird ausgelöst, wenn eine Anwendung versucht, null zu verwenden, wenn ein Objekt erforderlich ist. Diese beinhalten:

  • Aufruf der Instanzmethode eines Nullobjekts.
  • Zugriff auf oder Änderung des Felds eines Nullobjekts.
  • Nehmen Sie die Länge von Null, als wäre es ein Array.
  • Zugreifen auf oder Ändern der Slots von null, als wäre es ein Array.
  • Null werfen, als wäre es ein Throwable-Wert.

Anwendungen sollten Instanzen dieser Klasse auslösen, um andere illegale Verwendungen des Null-Objekts anzuzeigen.

Es ist auch der Fall, dass, wenn Sie versuchen, eine Nullreferenz mit zu verwenden synchronized, diese Ausnahme gemäß JLS ebenfalls ausgelöst wird :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Andernfalls NullPointerExceptionwird a ausgelöst , wenn der Wert des Ausdrucks null ist.

Wie behebe ich das?

Also hast du eine NullPointerException. Wie behebt man das? Nehmen wir ein einfaches Beispiel, das Folgendes auslöst 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();
    }
}

Identifizieren Sie die Nullwerte

Der erste Schritt besteht darin, genau zu identifizieren, welche Werte die Ausnahme verursachen . Dazu müssen wir einige Fehler beheben. Es ist wichtig zu lernen, wie man einen Stacktrace liest . Dies zeigt Ihnen, wo die Ausnahme ausgelöst wurde:

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)

Hier sehen wir, dass die Ausnahme in Zeile 13 (in der printStringMethode) ausgelöst wird . Sehen Sie sich die Zeile an und überprüfen Sie, welche Werte null sind, indem Sie Protokollierungsanweisungen hinzufügen oder einen Debugger verwenden . Wir finden heraus, dass dies snull ist, und das Aufrufen der lengthMethode löst die Ausnahme aus. Wir können sehen, dass das Programm die Ausnahme nicht mehr auslöst, wenn s.length()sie aus der Methode entfernt wird.

Verfolgen Sie, woher diese Werte stammen

Überprüfen Sie als nächstes, woher dieser Wert stammt. Indem Sie den Anrufer des Verfahrens sehen wir , dass sin mit übergeben wird printString(name)in derprint() Verfahren, und this.nameist null.

Verfolgen Sie, wo diese Werte eingestellt werden sollen

Wo ist this.nameeingestellt? In der setName(String)Methode. Mit etwas mehr Debugging können wir sehen, dass diese Methode überhaupt nicht aufgerufen wird. Wenn die Methode aufgerufen wurde, überprüfen Sie die Reihenfolge , in der diese Methoden aufgerufen werden, und die set-Methode wird nicht aufgerufen nach der Druckmethode .

Dies reicht aus, um eine Lösung zu finden: Fügen Sie einen Anruf hinzu, printer.setName()bevor Sie anrufenprinter.print() .

Andere Korrekturen

Die Variable kann einen Standardwert haben (und setNameverhindern, dass sie auf null gesetzt wird):

private String name = "";

Entweder die Methode printoder printStringkann nach null suchen , zum Beispiel:

printString((name == null) ? "" : name);

Oder Sie können die Klasse so gestalten, dass sie name immer einen Wert ungleich Null hat :

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

Siehe auch:

Ich kann das Problem immer noch nicht finden

Wenn Sie versucht haben, das Problem zu debuggen, und immer noch keine Lösung gefunden haben, können Sie eine Frage stellen, um weitere Hilfe zu erhalten. Geben Sie jedoch an, was Sie bisher versucht haben. Fügen Sie mindestens die Stapelverfolgung in die Frage ein und markieren Sie die wichtigen Zeilennummern im Code. Versuchen Sie auch, den Code zuerst zu vereinfachen (siehe SSCCE ).

fgb
quelle
44
+1 Gut, ein Beispiel zu haben, das das Durchlaufen des Stacktraces beinhaltet; Es ist wichtig zu zeigen, warum das Lesen für das Debuggen von NPE wichtig ist. (und warum wir fast immer nach einem Stacktrace suchen, wenn jemand eine Frage zu einem Fehler stellt)
Dennis Meng
16
Sie haben das Debuggen erwähnt ... Wie funktioniert das? Ich habe das Thema schon eine Weile recherchiert, kann aber nichts finden. Ich bin sicher, ein großartiger Lehrer wie Sie kann es mir in einer Sekunde beibringen! Vielen Dank! :-)
Ruchir Baronia
15
@RuchirBaronia Mit einem Debugger können Sie zeilenweise durch ein Programm gehen, um zu sehen, welche Methoden aufgerufen und wie Variablen geändert werden. IDEs sollten einige Tools haben, um dies zu tun. Siehe zum Beispiel vogella.com/tutorials/EclipseDebugging/article.html .
FGB
15
@RuchirBaronia Sie setzen Haltepunkte für die Methoden um NullPointerExceptions, wie im Stacktrace angezeigt, und vergleichen die Werte von Variablen mit den erwarteten Werten. Wenn Sie wissen, dass eine Variable null ist, wenn dies nicht der Fall sein sollte, können Sie Haltepunkte für jeden Code festlegen, der den Wert ändert. Es gibt auch bedingte Haltepunkte, die Sie verwenden können, um zu erfahren, wann sich ein Wert ändert.
FGB
6
Das Festlegen von Zeichenfolgenobjekten auf eine leere Zeichenfolge als Standardwert wird als schlechte Vorgehensweise angesehen.
Winzig
501

Frage: Was verursacht a NullPointerException (NPE)?

Wie Sie wissen sollten, sind Java - Typen unterteilt primitive Typen ( boolean, intusw.) und Referenztypen . Mit Referenztypen in Java können Sie den speziellen Wert verwendennull , mit dem Java "kein Objekt" sagt.

A NullPointerExceptionwird zur Laufzeit ausgelöst, wenn Ihr Programm versucht, a nullso zu verwenden, als wäre es eine echte Referenz. Zum Beispiel, wenn Sie dies schreiben:

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

Die Anweisung mit der Bezeichnung "HERE" versucht, die length()Methode für eine nullReferenz auszuführen , und dies löst a ausNullPointerException .

Es gibt viele Möglichkeiten, wie Sie einen nullWert verwenden können, der zu a führt NullPointerException. In der Tat sind die einzigen Dinge, die Sie mit einem tun können , nullohne eine NPE zu verursachen ,:

  • Weisen Sie es einer Referenzvariablen zu oder lesen Sie es aus einer Referenzvariablen.
  • Weisen Sie es einem Array-Element zu oder lesen Sie es aus einem Array-Element (vorausgesetzt, die Array-Referenz selbst ist nicht null!).
  • Übergeben Sie es als Parameter oder geben Sie es als Ergebnis zurück, oder
  • testen Sie die Verwendung ==oder !=Operatoren oder instanceof.

Frage: Wie lese ich den NPE-Stacktrace?

Angenommen, ich kompiliere und führe das obige Programm aus:

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

Erste Beobachtung: Die Zusammenstellung ist erfolgreich! Das Problem im Programm ist KEIN Kompilierungsfehler. Es ist ein Laufzeitfehler . (Einige IDEs warnen möglicherweise, dass Ihr Programm immer eine Ausnahme auslöst ... aber den Standardjavac Compiler jedoch nicht.)

Zweite Beobachtung: Wenn ich das Programm starte, werden zwei Zeilen "Gobbledy-Gook" ausgegeben. FALSCH!! Das ist kein Gobbledy-Gook. Es ist eine Stapelverfolgung ... und liefert wichtige Informationen , mit denen Sie den Fehler in Ihrem Code aufspüren können, wenn Sie sich die Zeit nehmen, ihn sorgfältig zu lesen.

Schauen wir uns also an, was darin steht:

Exception in thread "main" java.lang.NullPointerException

Die erste Zeile der Stapelverfolgung enthält eine Reihe von Informationen:

  • Hier erfahren Sie den Namen des Java-Threads, in dem die Ausnahme ausgelöst wurde. Für ein einfaches Programm mit einem Thread (wie diesem) ist es "main". Lass uns weitermachen ...
  • Es zeigt Ihnen den vollständigen Namen der Ausnahme, die ausgelöst wurde. dh java.lang.NullPointerException.
  • Wenn der Ausnahme eine Fehlermeldung zugeordnet ist, wird diese nach dem Ausnahmenamen ausgegeben. NullPointerExceptionist in dieser Hinsicht ungewöhnlich, da es selten eine Fehlermeldung gibt.

Die zweite Zeile ist die wichtigste bei der Diagnose einer NPE.

at Test.main(Test.java:4)

Dies sagt uns eine Reihe von Dingen:

  • "at Test.main" sagt, dass wir in der mainMethode der TestKlasse waren.
  • "Test.java:4" gibt den Quelldateinamen der Klasse an UND gibt an, dass sich die Anweisung, in der dies aufgetreten ist, in Zeile 4 der Datei befindet.

Wenn Sie die Zeilen in der obigen Datei zählen, ist Zeile 4 diejenige, die ich mit dem Kommentar "HIER" gekennzeichnet habe.

Beachten Sie, dass in einem komplizierteren Beispiel viele Zeilen in der NPE-Stapelverfolgung enthalten sind. Sie können jedoch sicher sein, dass die zweite Zeile (die erste "at" -Zeile) Ihnen sagt, wohin die NPE geworfen wurde 1 .

Kurz gesagt, der Stack-Trace sagt uns eindeutig, welche Anweisung des Programms die NPE ausgelöst hat.

1 - Nicht ganz richtig. Es gibt Dinge, die als verschachtelte Ausnahmen bezeichnet werden ...

Frage: Wie finde ich die Ursache der NPE-Ausnahme in meinem Code?

Das ist der schwierige Teil. Die kurze Antwort besteht darin, logische Rückschlüsse auf die vom Stack-Trace, dem Quellcode und der entsprechenden API-Dokumentation bereitgestellten Beweise zu ziehen.

Lassen Sie uns zunächst anhand des einfachen Beispiels (oben) veranschaulichen. Wir beginnen mit einem Blick auf die Linie, die uns die Stapelverfolgung mitgeteilt hat, wo die NPE passiert ist:

int length = foo.length(); // HERE

Wie kann das eine NPE werfen?

In der Tat gibt es nur einen Weg: Es kann nur passieren, wenn fooder Wert hat null. Wir versuchen dann, die length()Methode auszuführen nullund ... BANG!

Aber (ich höre Sie sagen) was ist, wenn die NPE in den length()Methodenaufruf geworfen wurde ?

In diesem Fall würde die Stapelverfolgung anders aussehen. Die erste "at" -Zeile würde sagen, dass die Ausnahme in einer Zeile in der java.lang.StringKlasse ausgelöst wurde, und Zeile 4 von Test.javawäre die zweite "at" -Zeile.

Woher kam das null? In diesem Fall ist es offensichtlich, und es ist offensichtlich, was wir tun müssen, um das Problem zu beheben. (Weisen Sie einen Wert ungleich Null zufoo .)

OK, versuchen wir es mit einem etwas kniffligeren Beispiel. Dies erfordert einen logischen Abzug .

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)
$ 

Jetzt haben wir also zwei "at" -Linien. Der erste ist für diese Zeile:

return args[pos].length();

und der zweite ist für diese Zeile:

int length = test(foo, 1);

Wie könnte das in der ersten Zeile eine NPE werfen? Es gibt zwei Möglichkeiten:

  • Wenn der Wert barist nulldann bar[pos]wird ein NPE werfen.
  • Wenn der Wert bar[pos]wird nulldann Aufruf length()an wird es eine NPE werfen.

Als nächstes müssen wir herausfinden, welches dieser Szenarien erklärt, was tatsächlich passiert. Wir beginnen mit der Erkundung des ersten:

Woher kommt bardas? Es ist ein Parameter für den testMethodenaufruf, und wenn wir uns ansehen, wie testaufgerufen wurde, können wir sehen, dass er von der foostatischen Variablen stammt. Außerdem können wir deutlich sehen, dass wir fooauf einen Wert ungleich Null initialisiert haben. Dies reicht aus, um diese Erklärung vorläufig abzulehnen. (Theoretisch könnte etwas anderes ändern foo zunull ... aber das passiert hier nicht.)

Was ist also mit unserem zweiten Szenario? Nun, wir können sehen, dass das so posist 1, das heißt, das foo[1]muss sein null. Ist das möglich?

Tatsächlich ist es! Und das ist das Problem. Wenn wir so initialisieren:

private static String[] foo = new String[2];

Wir ordnen a String[]mit zwei Elementen zu , die initialisiert werdennull . Danach haben wir den Inhalt nicht verändert foo... so foo[1]wird immer noch null.

Stephen C.
quelle
425

Es ist, als ob Sie versuchen, auf ein Objekt zuzugreifen, das ist null. Betrachten Sie das folgende Beispiel:

TypeA objA;

Zu diesem Zeitpunkt haben Sie dieses Objekt gerade deklariert, aber nicht initialisiert oder instanziiert . Und wenn Sie versuchen, auf eine Eigenschaft oder Methode darin zuzugreifen, wird dies ausgelöst NullPointerException, was Sinn macht.

Siehe auch das folgende Beispiel:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Rakesh Burbure
quelle
1
Wenn wir System.out.println (a.length ()) geben; // NullPointerException wird ausgelöst, um dies zu überspringen, können wir mit try catch block umgehen. Vielen Dank
Vijaya Varma Lanke
359

Eine Nullzeigerausnahme wird ausgelöst, wenn eine Anwendung versucht, Null zu verwenden, wenn ein Objekt erforderlich ist. Diese beinhalten:

  1. Aufruf der Instanzmethode eines nullObjekts.
  2. Auf das Feld eines nullObjekts zugreifen oder es ändern .
  3. Nehmen Sie die Länge, nullals wäre es ein Array.
  4. Zugreifen auf oder Ändern der Slots von nullals wäre es ein Array.
  5. Werfen, nullals wäre es ein Wurfwert.

Anwendungen sollten Instanzen dieser Klasse auslösen, um andere illegale Verwendungen von anzuzeigen null Objekts .

Referenz: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

nathan1138
quelle
12
Halten Sie es einfach, ich mag diese Antwort, fügen Sie dies hinzu, wenn Sie es für richtig halten - Zugriff auf nicht initialisierte Attribute eines Objekts
Emiliano
5
@Emiliano - der einfache Zugriff auf ein initialisiertes Attribut verursacht keine NPE. Es ist das, was Sie >> mit dem nicht initialisierten Attributwert tun, der die NPE verursacht.
Stephen C
1
Wenn Sie mehr Fälle wünschen: 1) Verwenden von a nullals Ziel eines synchronizedBlocks, 2) Verwenden von a nullals Ziel von a switchund Entpacken null.
Stephen C
333

Ein nullZeiger zeigt auf nichts. Wenn Sie einen Zeiger dereferenzieren p, sagen Sie "Geben Sie mir die Daten an dem in" p "gespeicherten Ort. Wenn pein nullZeiger ist, ist der Ort, an dem er gespeichert pist nowhere," Geben Sie mir die Daten an dem Ort 'nirgendwo' ". Offensichtlich kann es das nicht, also wirft es einnull pointer exception .

Im Allgemeinen liegt es daran, dass etwas nicht richtig initialisiert wurde.

MrZebra
quelle
2
Erstellen wir eine Datenbank? -> NULList wie nullin Java geschrieben. Und es ist eine Sache, bei der zwischen Groß- und Kleinschreibung unterschieden wird.
bvdb
3
"Ein NULL-Zeiger zeigt auf nichts" Ich bin anderer Meinung. Nullzeiger zeigen nicht auf das Nirgendwo, sondern auf Nullwerte.
TheRealChx101
2
@ TheRealChx101 Ein Nullzeiger und ein Zeiger auf einen Nullwert sind verschiedene Dinge - ein Nullzeiger zeigt nicht auf einen Nullwert. Angenommen, Sie haben einen Zeiger auf einen Zeiger: Zeiger A zeigt auf Zeiger B, und Zeiger B ist null. In diesem Fall zeigt Zeiger A auf einen Nullwert, und Zeiger B ist ein Nullzeiger.
MrZebra
321

Es gibt bereits viele Erklärungen, um zu erklären, wie es passiert und wie es behoben werden kann. Sie sollten jedoch auch bewährte Methoden befolgen , um NullPointerExceptions überhaupt zu vermeiden .

Siehe auch: Eine gute Liste bewährter Methoden

Ich würde hinzufügen, sehr wichtig, den finalModifikator gut zu nutzen . Verwenden des Modifikators "final", wann immer dies in Java anwendbar ist

Zusammenfassung:

  1. Verwenden Sie den finalModifikator, um eine gute Initialisierung zu erzwingen.
  2. Vermeiden Sie die Rückgabe von Null in Methoden, z. B. die Rückgabe leerer Sammlungen, falls zutreffend.
  3. Verwenden Sie Anmerkungen @NotNull und@Nullable
  4. Scheitern Sie schnell und verwenden Sie Asserts, um die Weitergabe von Nullobjekten durch die gesamte Anwendung zu vermeiden, wenn sie nicht Null sein sollten.
  5. Verwenden Sie zuerst gleich mit einem bekannten Objekt: if("knownObject".equals(unknownObject)
  6. Bevorzugen valueOf() als toString().
  7. Verwenden Sie null safe StringUtils Methoden StringUtils.isEmpty(null).
  8. Verwenden Sie Java 8 Optional als Rückgabewert in Methoden. Die optionale Klasse bietet eine Lösung für die Darstellung optionaler Werte anstelle von Nullreferenzen.
LG
quelle
4
In j2ee-Projekten ist die Nullpointer-Ausnahme sehr häufig. In einigen Fällen haben Referenzvariablen Nullwerte. Sie sollten die Variableninitialisierung ordnungsgemäß überprüfen. Und während der bedingten Anweisung sollten Sie immer überprüfen, ob das Flag oder die Referenz null enthält oder nicht wie folgt: - if (flag! = 0) {Ihr Code, der Flagge verwendet}
Amaresh Pattanayak
14
Es ist erwähnenswert, dass einige IDEs (z. B. Eclipse) automatische Nullheitsanalysen basierend auf anpassbaren Anmerkungen (z. B. @Nullablewie oben aufgeführt ) anbieten und vor möglichen Fehlern warnen. Es ist auch möglich, solche Anmerkungen basierend auf der vorhandenen Codestruktur abzuleiten und zu generieren (z. B. kann IntelliJ dies tun).
Jan Chimiak
4
Bevor Sie ein nullbares Objekt verwenden, sollten Sie zunächst überprüfen, ob es null ist. Verwenden Sie if (obj==null).Wenn es null ist, sollten Sie Code schreiben, um dies ebenfalls zu handhaben.
Lakmal Vithanage
4
IMO ist es vorzuziehen, die Rückgabe von Nullobjekten in Methoden nach Möglichkeit zu vermeiden und Annotationen zu verwenden, wenn Null-Eingabeparameter nicht zulässig sind, um vertraglich die Menge von ´if (obj == null) ´ im Code zu reduzieren und die zu verbessern Lesbarkeit des Codes.
LG
4
Lesen Sie dies ... bevor Sie diese "Best Practices" als wahr
Stephen C
316

In Java hat alles (außer primitiven Typen) die Form einer Klasse.

Wenn Sie ein Objekt verwenden möchten, haben Sie zwei Phasen:

  1. Erklären
  2. Initialisierung

Beispiel:

  • Erklärung: Object object;
  • Initialisierung: object = new Object();

Gleiches gilt für das Array-Konzept:

  • Erklärung: Item item[] = new Item[5];
  • Initialisierung: item[0] = new Item();

Wenn Sie den Initialisierungsabschnitt nicht angeben, NullPointerExceptionentsteht der.

ashish bhatt
quelle
3
Eine NullPointerException tritt häufig auf, wenn die Methode einer Instanz aufgerufen wird. Wenn Sie beispielsweise eine Referenz deklarieren, diese jedoch nicht auf eine Instanz verweist, tritt beim Aufrufen der Methode eine NullPointerException auf. wie zum Beispiel: YourClass ref = null; // oder ref = anotherRef; // aber anotherRef hat auf keine Instanz verwiesen ref.someMethod (); // Es wird eine NullPointerException ausgelöst. Beheben Sie dies im Allgemeinen folgendermaßen: Bevor Sie die Methode aufrufen, stellen Sie fest, ob die Referenz null ist. wie zum Beispiel: if (yourRef! = null) {yourRef.someMethod (); }
Sunhang
2
Oder verwenden Sie die Ausnahmeerfassung: Beispiel: try {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
Sunhang
315

Eine Nullzeigerausnahme ist ein Indikator dafür, dass Sie ein Objekt verwenden, ohne es zu initialisieren.

Im Folgenden finden Sie beispielsweise eine Schülerklasse, die sie in unserem Code verwendet.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Der folgende Code gibt Ihnen eine Nullzeigerausnahme.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Weil Sie verwenden student, aber vergessen haben, es wie im richtigen Code unten zu initialisieren:

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");
        }
    }
}
javid piprani
quelle
7
Obwohl dies ein schönes Beispiel ist, darf ich fragen, was es zu der Frage hinzufügt, die nicht bereits von allen anderen Antworten abgedeckt wird?
Mysticial
13
Es ist einfach unangemessen, hier das Wort "nicht initialisiert" zu verwenden. Das von Ihnen gezeigte Beispiel ist tatsächlich "initialisiert" und wird mit null initialisiert. Bei nicht initialisierten Variablen wird sich der Compiler bei Ihnen beschweren.
Adrian Shum
2
Eine NPE kann ein Indikator dafür sein, dass Sie ein nicht initialisiertes Feld verwenden. Dies kann ein Indikator dafür sein, dass Sie andere Dinge tun. Eine zu starke Vereinfachung auf eine einzelne Ursache wie diese hilft niemandem, NPE-Probleme zu lösen ... wenn die eigentliche Ursache nicht diese ist.
Stephen C
309

In Java sind alle von Ihnen deklarierten Variablen "Verweise" auf die Objekte (oder Grundelemente) und nicht auf die Objekte selbst.

Wenn Sie versuchen, eine Objektmethode auszuführen, fordert die Referenz das lebende Objekt auf, diese Methode auszuführen. Wenn die Referenz jedoch auf NULL verweist (nichts, null, nichtig, nada), kann die Methode auf keinen Fall ausgeführt werden. Dann teilt Ihnen die Laufzeit dies mit, indem Sie eine NullPointerException auslösen.

Ihre Referenz ist "Zeigen" auf Null, also "Null -> Zeiger".

Das Objekt befindet sich im VM-Speicher und kann nur mithilfe von thisReferenzen darauf zugreifen . Nehmen Sie dieses Beispiel:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

Und an einer anderen Stelle in Ihrem Code:

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

Dies ist eine wichtige Sache zu wissen - wenn es keine Verweise mehr auf ein Objekt gibt (im obigen Beispiel, wenn referenceund otherReferencebeide auf null zeigen), ist das Objekt "nicht erreichbar". Wir können auf keinen Fall damit arbeiten, sodass dieses Objekt für die Speicherbereinigung bereit ist. Irgendwann gibt die VM den von diesem Objekt verwendeten Speicher frei und weist ein anderes zu.

OscarRyz
quelle
280

Ein anderes Auftreten von a NullPointerExceptiontritt auf, wenn man ein Objektarray deklariert und dann sofort versucht, darin enthaltene Elemente zu dereferenzieren.

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

Diese spezielle NPE kann vermieden werden, wenn die Vergleichsreihenfolge umgekehrt wird. nämlich verwenden.equals für ein garantiertes Nicht-Null-Objekt.

Alle Elemente innerhalb eines Arrays werden auf ihren gemeinsamen Anfangswert initialisiert . Für jede Art von Objektarray bedeutet dies, dass alle Elemente vorhanden sindnull .

Sie müssen die Elemente im Array initialisieren, bevor Sie auf sie zugreifen oder sie dereferenzieren können.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}
Makoto
quelle
Eine Operation für ein nicht initialisiertes Objekt auf Instanzebene (nicht auf Klassenebene) führt zu NullPointerException. Die Operation muss instanzspezifisch sein. Wenn sich die Operation auf Klassenebene befindet und beispielsweise eine statische Methode für ein nicht initialisiertes Objekt aufgerufen wird, wird keine NullPointerException-Ausnahme ausgelöst. Selbst primitive Wrapper-Klassenobjekte lösen eine NullPointerException aus.
Shailendra Singh
1. NullPointerException ist eine RuntimeException, das heißt, sie wird angezeigt, wenn Ihr Programm ausgeführt wird, nicht zur Kompilierungszeit.! :(, aber die meisten IDE helfen Ihnen dabei, dies
herauszufinden
@ tomj0101 Ich bin mir völlig unklar, warum Sie diesen Kommentar abgegeben haben ... Aber zu Ihrem zweiten Punkt war ein vorheriges Muster Optional, null zurückzugeben. Das Schlüsselwort ist in Ordnung. Es ist wichtig zu wissen, wie man sich dagegen schützt. Dies bietet ein häufiges Auftreten und Möglichkeiten, es zu mildern.
Makoto
NullPointerException ist eine Laufzeitausnahme, die nicht zum Abfangen empfohlen, sondern vermieden wird .
Shomu
2
@ Shomu: Ab wann schlage ich überhaupt vor, dass es gefangen werden sollte?
Makoto