Was ist eine NullPointerException und wie behebe ich sie?

211

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

Welche Methoden / Tools können verwendet werden, um die Ursache zu ermitteln, sodass Sie verhindern, dass die Ausnahme das Programm vorzeitig beendet?

    
Ziggy 26.05.2016, 16:15
quelle

12 Antworten

2945

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

%Vor%

In diesem Beispiel ist die Variable x ein int und Java initialisiert es für Sie auf 0. Wenn Sie es in der zweiten Zeile auf 10 setzen, wird Ihr Wert 10 in den Speicherplatz geschrieben, auf den x zeigt.

Aber wenn Sie versuchen, einen Referenztyp zu deklarieren, passiert etwas anderes. Nimm den folgenden Code:

%Vor%

Die erste Zeile deklariert eine Variable mit dem Namen num , aber sie enthält keinen primitiven Wert. Stattdessen enthält es einen Zeiger (weil der Typ Integer ist, was ein Referenztyp ist). Da Sie noch nicht gesagt haben, was Sie auf Java zeigen sollen, setzen Sie es auf null, was bedeutet " Ich zeige auf nichts ".

In der zweiten Zeile wird das Schlüsselwort new verwendet, um ein Objekt vom Typ Integer zu instanziieren (oder zu erstellen), und der Zeigervariable num wird dieses Objekt zugewiesen. Sie können nun mit dem Dereferenzierungsoperator . (ein Punkt) auf das Objekt verweisen.

Das Exception , nach dem Sie gefragt haben, tritt auf, wenn Sie eine Variable deklarieren, aber kein Objekt erstellt haben. Wenn Sie versuchen, num zu dereferenzieren, BEVOR Sie das Objekt erstellen, erhalten Sie NullPointerException . In den einfachsten Fällen wird der Compiler das Problem abfangen und Sie wissen lassen, dass "num möglicherweise nicht initialisiert wurde", aber manchmal schreiben Sie Code, der das Objekt nicht direkt erstellt.

Sie können zum Beispiel eine Methode wie folgt haben:

%Vor%

In diesem Fall erstellen Sie nicht das Objekt obj , sondern nehmen an, dass es erstellt wurde, bevor die Methode doSomething aufgerufen wurde. Leider ist es möglich, die Methode wie folgt aufzurufen:

%Vor%

In diesem Fall ist obj gleich Null. Wenn die Methode etwas mit dem übergebenen Objekt tun soll, ist es angebracht, NullPointerException zu werfen, weil es sich um einen Programmierfehler handelt und der Programmierer diese Information zu Debugging-Zwecken benötigt.

Alternativ kann es Fälle geben, in denen der Zweck der Methode nicht nur darin besteht, mit dem übergebenen Objekt zu arbeiten, und daher ein Null-Parameter akzeptabel sein kann. In diesem Fall müssten Sie nach einem Null-Parameter suchen und sich anders verhalten. Sie sollten dies auch in der Dokumentation erläutern. Zum Beispiel könnte doSomething wie folgt geschrieben werden:

%Vor%

Zum Schluss: Wie Sie den Ausnahmeort & amp; Ursache für die Verwendung von Stack Trace

    
Vincent Ramdhanie 26.03.2018, 09:34
quelle
707

NullPointerException s sind Ausnahmen, die auftreten, wenn Sie versuchen, einen Verweis zu verwenden, der auf keinen Speicherort im Speicher verweist (null), als ob er auf ein Objekt verweist. Wenn Sie eine Methode für eine Nullreferenz aufrufen oder versuchen, auf ein Feld einer Nullreferenz zuzugreifen, wird NullPointerException ausgelöst. Diese sind am häufigsten, aber andere Möglichkeiten sind auf der NullPointerException Javadoc-Seite.

Der wahrscheinlich schnellste Beispielcode, den ich zur Veranschaulichung eines NullPointerException erstellen könnte, wäre:

%Vor%

In der ersten Zeile in main setze ich explizit Object reference obj auf null . Das bedeutet, ich habe eine Referenz, aber sie zeigt nicht auf ein Objekt. Danach versuche ich, die Referenz so zu behandeln, als ob sie auf ein Objekt zeigt, indem ich eine Methode darauf anrufe. Dies führt zu NullPointerException , da an der Stelle, auf die die Referenz verweist, kein Code ausgeführt werden muss.

(Dies ist ein technischer Aspekt, aber ich denke, es erwähnt: Ein Verweis, der auf Null zeigt, ist nicht dasselbe wie ein C-Zeiger, der auf einen ungültigen Speicherort zeigt. Ein Nullzeiger zeigt nirgends , was subtil anders ist, als auf einen Ort zu zeigen, der zufällig ungültig ist.)

    
Bill the Lizard 25.12.2017 14:24
quelle
563

Was ist eine NullPointerException?

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

  

Wird ausgelöst, wenn eine Anwendung versucht, in einem Fall null zu verwenden   Objekt ist erforderlich. Dazu gehören:

     
  • Aufruf der Instanzmethode eines Null-Objekts.
  •   
  • Auf das Feld eines Nullobjekts zugreifen oder dieses ändern.
  •   
  • Die Länge von null als wäre es ein Array.
  •   
  • Auf die Slots von null zugreifen oder sie ändern, als wäre es ein Array.
  •   
  • Nullen wird geworfen, als wäre es ein Throwable-Wert.
  •   

Anwendungen sollten Instanzen dieser Klasse abwerfen, um andere anzugeben   Illegale Verwendung des Null-Objekts.

Wenn Sie versuchen, einen NULL-Verweis mit synchronized zu verwenden, wird auch diese Ausnahme ausgelöst. nach der JLS :

%Vor%      
  • Andernfalls, wenn der Wert des Ausdrucks null ist, wird ein NullPointerException geworfen.
  •   

Wie behebe ich es?

Sie haben also ein NullPointerException . Wie reparierst du es? Nehmen wir ein einfaches Beispiel, das ein NullPointerException :

auslöst %Vor%

Identifizieren Sie die Nullwerte

Der erste Schritt besteht darin, genau zu identifizieren, welche Werte die Ausnahme verursachen . Dafür müssen wir etwas debuggen. Es ist wichtig zu lernen, einen Stacktrace zu lesen. Dies zeigt Ihnen, wo die Ausnahme ausgelöst wurde:

%Vor%

Hier sehen wir, dass die Ausnahme in Zeile 13 (in der Methode printString ) ausgelöst wird. Sehen Sie sich die Zeile an und prüfen Sie, um welche Werte es sich bei null handelt Hinzufügen von Protokollierungsanweisungen oder Verwenden eines Debuggers . Wir finden heraus, dass s gleich null ist und der Aufruf der Methode length die Ausnahme auslöst. Wir können sehen, dass das Programm aufhört, die Ausnahme auszulösen, wenn s.length() aus der Methode entfernt wird.

Verfolgen Sie, woher diese Werte stammen

Als nächstes überprüfen Sie, woher dieser Wert kommt. Indem wir den Aufrufern der Methode folgen, sehen wir, dass s mit printString(name) in der Methode print() übergeben wird und this.name null ist.

Verfolgen Sie, wo diese Werte festgelegt werden sollen

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

Das ist genug, um uns eine Lösung zu geben: Fügen Sie einen Aufruf von printer.setName() hinzu, bevor Sie printer.print() aufrufen.

Andere Korrekturen

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

%Vor%

Entweder die Methode print oder printString kann auf null prüfen, zum Beispiel:

%Vor%

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

%Vor%

Siehe auch:

Ich kann das Problem immer noch nicht finden

Wenn Sie versucht haben, das Problem zu beheben und immer noch keine Lösung haben, können Sie eine Frage für weitere Hilfe stellen, aber stellen Sie sicher, dass Sie das, was Sie bisher versucht haben, einbeziehen. Mindestens enthält das Stacktrace in der Frage und markiert die wichtigen Zeilennummern im Code. Versuchen Sie auch, den Code zuerst zu vereinfachen (siehe SSCCE ).

    
fgb 29.12.2017 13:53
quelle
393

Frage: Was verursacht NullPointerException (NPE)?

Wie Sie wissen sollten, sind Java-Typen in primitive Typen ( boolean , int usw.) und Referenztypen unterteilt. Referenztypen in Java erlauben Ihnen, den speziellen Wert null zu verwenden, was die Java-Art ist, "kein Objekt" zu sagen.

Ein NullPointerException wird zur Laufzeit ausgelöst, wenn Ihr Programm versucht, ein null zu verwenden, als wäre es eine echte Referenz. Zum Beispiel, wenn Sie dies schreiben:

%Vor%

Die Anweisung "HIER" wird versuchen, die length() -Methode für einen null -Referenz auszuführen, und dies wird ein NullPointerException werfen.

Es gibt viele Möglichkeiten, einen null -Wert zu verwenden, der zu einem NullPointerException führt. Die einzigen Dinge, die Sie mit einem null ausführen können, ohne eine NPE zu verursachen, sind:

  • weisen Sie es einer Referenzvariablen zu oder lesen Sie es aus einer Referenzvariablen
  • weisen Sie es einem Array-Element zu oder lesen Sie es von einem Array-Element (vorausgesetzt, dass das Array selbst nicht-null ist!),
  • übergeben Sie es als Parameter oder geben Sie es als Ergebnis oder
  • zurück
  • Testen Sie es mit den Operatoren == oder != oder instanceof .

Frage: Wie lese ich den NPE StackTrace?

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

%Vor%

Erste Beobachtung: Die Kompilation ist erfolgreich! Das Problem im Programm ist KEIN Kompilierungsfehler. Es ist ein Fehler Laufzeit . (Einige IDEs warnen möglicherweise, dass Ihr Programm immer eine Ausnahme auslöst ... aber der standardmäßige javac Compiler tut dies nicht.)

Zweite Beobachtung: Wenn ich das Programm laufe, gibt es zwei Zeilen "gobleddy-gook" aus. FALSCH !! Das ist kein Kauderwelsch. Es ist ein StackTrace ... und liefert wichtige Informationen , die Ihnen helfen, den Fehler in Ihrem Code aufzuspüren, wenn Sie sich die Zeit nehmen, ihn sorgfältig zu lesen.

Sehen wir uns also an, was es sagt:

%Vor%

Die erste Zeile des Stack-Trace zeigt Ihnen eine Reihe von Dingen:

  • Er gibt Ihnen den Namen des Java-Threads an, in dem die Ausnahme ausgelöst wurde. Für ein einfaches Programm mit einem Thread (wie diesem) ist es "main". Gehen wir weiter ...
  • Es gibt Ihnen den vollständigen Namen der ausgelösten Ausnahme; d.h. java.lang.NullPointerException .
  • Wenn der Ausnahme eine Fehlermeldung zugeordnet ist, wird diese nach dem Namen der Ausnahme ausgegeben. NullPointerException ist in dieser Hinsicht ungewöhnlich, da es selten eine Fehlermeldung gibt.

Die zweite Zeile ist die wichtigste für die Diagnose einer NPE.

%Vor%

Dies sagt uns eine Reihe von Dingen:

  • "at Test.main" sagt, dass wir uns in der main -Methode der Test -Klasse befanden.
  • "Test.java:4" gibt den Quelldateinamen der Klasse an UND sagt uns, dass die Anweisung, wo dies geschah, in Zeile 4 der Datei steht.

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

Beachten Sie, dass in einem komplizierteren Beispiel viele Zeilen in der NPE-Stack-Ablaufverfolgung vorhanden sind. Aber Sie können sicher sein, dass die zweite Zeile (die erste "at" -Zeile) Ihnen sagen wird, wo die NPE geworfen wurde 1 .

Kurz gesagt, der Stack-Trace wird uns eindeutig sagen, welche Anweisung des Programms die NPE geworfen hat.

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

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

Das ist der schwierige Teil. Die kurze Antwort besteht darin, logische Folgerungen auf die vom Stack-Trace bereitgestellten Informationen, den Quellcode und die relevante API-Dokumentation anzuwenden.

Lassen Sie uns zuerst das einfache Beispiel (oben) erläutern. Wir beginnen damit, die Zeile zu betrachten, die der Stack-Trace uns mitgeteilt hat, wo die NPE passiert ist:

%Vor%

Wie kann das eine NPE werfen?

Tatsächlich gibt es nur einen Weg: Es kann nur passieren, wenn foo den Wert null hat. Wir versuchen dann, die Methode length() für null und .... BANG!

auszuführen

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

Nun, wenn das passierte, würde der Stack-Trace anders aussehen. Die erste "at" -Zeile würde sagen, dass die Ausnahme in einer Zeile in der java.lang.String -Klasse geworfen wurde, und die Zeile 4 von Test.java wäre die zweite "at" -Zeile.

Woher kommt also null ? In diesem Fall ist es offensichtlich, und es ist offensichtlich, was wir tun müssen, um es zu beheben. (Weisen Sie foo einen Wert ungleich null zu.)

OK, also versuchen wir ein etwas komplizierteres Beispiel. Dies erfordert einige logische Schlussfolgerungen .

%Vor%

So, jetzt haben wir zwei "at" -Linien. Der erste ist für diese Zeile:

%Vor%

und der zweite ist für diese Zeile:

%Vor%

Betrachtet man die erste Zeile, wie könnte das eine NPE werfen? Es gibt zwei Möglichkeiten:

  • Wenn der Wert von bar null ist, dann wird bar[pos] eine NPE werfen.
  • Wenn der Wert von bar[pos] null ist, dann ruft das Aufrufen von length() eine NPE auf.

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 bar ? Es ist ein Parameter für den Methodenaufruf test , und wenn wir uns ansehen, wie test aufgerufen wurde, können wir sehen, dass es von der statischen Variable foo kommt. Außerdem können wir klar sehen, dass foo auf einen Nicht-Null-Wert initialisiert wurde. Das reicht aus, um diese Erklärung vorläufig zu verwerfen. (Theoretisch könnte etwas anderes ändern foo zu null ... aber das passiert hier nicht.)

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

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

%Vor%

Wir weisen String[] mit zwei Elementen zu, die auf null initialisiert werden. Danach haben wir den Inhalt von foo ... nicht geändert, so dass foo[1] immer noch null ist.

    
Stephen C 19.03.2018 14:05
quelle
334

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

%Vor%

Zu diesem Zeitpunkt haben Sie nur dieses Objekt deklariert, aber nicht initialisiert oder instanziiert . Und wann immer Sie versuchen, auf eine Eigenschaft oder Methode zuzugreifen, wird NullPointerException ausgegeben, was Sinn macht.

Siehe auch das folgende Beispiel.

%Vor%     
Rakesh Burbure 21.02.2018 10:54
quelle
290

Eine Nullzeiger-Ausnahme wird ausgelöst, wenn eine Anwendung in einem Fall, in dem ein Objekt benötigt wird, versucht, null zu verwenden. Dazu gehören:

  1. Aufruf der Instanzmethode eines null -Objekts.
  2. Zugriff oder Änderung des Feldes eines null -Objekts.
  3. Nehmen Sie die Länge von null so, als wäre es ein Array.
  4. Auf die Slots von null zugreifen oder sie ändern, als wäre es ein Array.
  5. null wird geworfen, als wäre es ein Throwable-Wert.

Anwendungen sollten Instanzen dieser Klasse auslösen, um auf andere illegale Verwendungen des null -Objekts hinzuweisen.

Referenz: Ссылка

    
nathan1138 20.12.2017 21:40
quelle
267

Ein NULL -Zeiger ist einer, der nach nirgendwo zeigt. Wenn Sie einen Zeiger p dereferenzieren, sagen Sie "geben Sie mir die Daten an dem Speicherort in" p ". Wenn p ein Null-Zeiger ist, ist die in p gespeicherte Position nowhere , sagen Sie "Gib mir die Daten an der Stelle 'Nirgendwo'". Offensichtlich kann es das nicht, also wirft es ein NULL pointer exception .

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

    
MrZebra 25.12.2017 14:30
quelle
257

Es gibt bereits viele Erklärungen, die erklären, wie es passiert und wie Sie es beheben können. Sie sollten jedoch Best Practices befolgen, um NullPointerException überhaupt zu vermeiden.

Siehe auch: Eine gute Liste der Best Practices

Ich würde hinzufügen, sehr wichtig, nutze den final Modifikator gut. Verwenden des Modifizierers "final", wenn zutreffend in Java

Zusammenfassung:

  1. Verwenden Sie den Modifizierer final , um eine gute Initialisierung zu erzwingen.
  2. Vermeiden Sie das Zurückgeben von null in Methoden, z. B. das Zurücksenden leerer Sammlungen.
  3. Verwenden Sie die Anmerkungen @NotNull und @Nullable
  4. Fail fail und verwenden Sie die Option "answers", um die Weitergabe von Nullobjekten durch die gesamte Anwendung zu vermeiden, wenn sie nicht null sein sollten.
  5. Verwenden Sie gleich mit einem bekannten Objekt zuerst: if("knownObject".equals(unknownObject)
  6. Bevorzugt valueOf() über toString ().
  7. Verwenden Sie null safe StringUtils methods StringUtils.isEmpty(null) .
L. G. 25.12.2017 14:31
quelle
254

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

Zum Beispiel ist unten eine Schülerklasse, die sie in unserem Code verwenden wird.

%Vor%

Der folgende Code gibt Ihnen eine Nullzeigerausnahme.

%Vor%

Weil du Obj_Student benutzt hast, aber du hast vergessen es zu initialisieren wie in der korrekter Code unten gezeigt:

%Vor%     
javid piprani 20.12.2017 21:44
quelle
240

In Java ist alles in der Form einer Klasse.

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

  1. Deklarieren
  2. Initialisierung

Beispiel:

  • Erklärung: int a;
  • Initialisierung: a=0;

Gleiches gilt für das Array-Konzept

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

Wenn Sie den Initialisierungsabschnitt nicht angeben, entsteht die NullpointerException .

    
ashish bhatt 25.12.2017 14:32
quelle
233

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

Wenn Sie versuchen, eine Objektmethode auszuführen, fordert die Referenz das Objekt living auf, diese Methode auszuführen. Aber wenn die Referenz auf NULL verweist (nichts, null, void, nada), gibt es keine Möglichkeit, die Methode auszuführen. Dann lässt Sie die Laufzeit wissen, indem Sie eine NullPointerException werfen.

Ihre Referenz verweist auf null, also "Null - Zeiger".

Das Objekt befindet sich im VM-Speicherbereich und die einzige Möglichkeit, darauf zuzugreifen, ist die Verwendung von this references. Nimm dieses Beispiel:

%Vor%

Dies ist wichtig zu wissen - wenn es keine Referenzen mehr auf ein Objekt gibt (im Beispiel oben, wenn reference und otherReference auf null zeigen), dann ist das Objekt "nicht erreichbar". Es gibt keine Möglichkeit, damit zu arbeiten, daher wird dieses Objekt als "Garbage Collected" markiert, und irgendwann wird die VM den Speicher freigeben, der von diesem Objekt verwendet wird, und ein anderes zuweisen.

    
OscarRyz 25.12.2017 14:34
quelle
221

Ein weiteres Vorkommen von NullPointerException tritt auf, wenn man ein Objekt-Array deklariert und dann sofort versucht, Elemente darin zu dereferenzieren.

%Vor%

Dieses spezielle NPE kann vermieden werden, wenn die Vergleichsreihenfolge umgekehrt wird; Verwenden Sie nämlich .equals auf einem garantierten Nicht-Null-Objekt.

Alle Elemente innerhalb eines Arrays werden initialisiert ihr gemeinsamer Anfangswert ; Für alle Arten von Objekt-Arrays bedeutet dies, dass alle Elemente null sind.

Sie müssen die Elemente im Array initialisieren, bevor auf sie zugreift oder die Dereferenzierung erfolgt.

%Vor%     
Makoto 25.12.2017 14:35
quelle

Tags und Links