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?
quelle
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?
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 x
eine int
und wird von Java 0
für Sie initialisiert . Wenn Sie ihm 10
in 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 Integer
ein 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 new
Schlüsselwort verwendet, um ein Objekt vom Typ zu instanziieren (oder zu erstellen), Integer
und die Zeigervariable num
wird diesem Integer
Objekt zugewiesen .
Dies NullPointerException
tritt 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 num
durchzuführen, bevor Sie das Objekt erstellen, erhalten Sie eine NullPointerException
. In den trivialsten Fällen num may not have been initialized
erkennt 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 obj
ist null
. Wenn die Methode etwas mit dem übergebenen Objekt tun soll, ist es angebracht, das auszulösen, NullPointerException
da 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?
int a=b
Kann eine NPE auslösen, wenn b eine istInteger
. Es gibt Fälle, in denen das Debuggen verwirrend ist.NullPointerException
Probleme in Ihrem Code zu vermeiden , ist die Verwendung von@Nullable
und@NotNull
Anmerkungen. 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?)NullPointerException
s 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östNullPointerException
. Dies sind die häufigsten, aber andere Möglichkeiten sind auf derNullPointerException
Javadoc-Seite aufgeführt.Der wahrscheinlich schnellste Beispielcode, den ich zur Veranschaulichung von a finden könnte,
NullPointerException
wäre:In der ersten Zeile
main
setze ich dieObject
Referenz explizitobj
aufnull
. 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.)
quelle
null
zuvor, 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?Was ist eine NullPointerException?
Ein guter Anfang sind die JavaDocs . Sie haben dies abgedeckt:
Es ist auch der Fall, dass, wenn Sie versuchen, eine Nullreferenz mit zu verwenden
synchronized
, diese Ausnahme gemäß JLS ebenfalls ausgelöst wird :Wie behebe ich das?
Also hast du eine
NullPointerException
. Wie behebt man das? Nehmen wir ein einfaches Beispiel, das Folgendes auslöstNullPointerException
: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:
Hier sehen wir, dass die Ausnahme in Zeile 13 (in der
printString
Methode) 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 diess
null ist, und das Aufrufen derlength
Methode löst die Ausnahme aus. Wir können sehen, dass das Programm die Ausnahme nicht mehr auslöst, wenns.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
s
in mit übergeben wirdprintString(name)
in derprint()
Verfahren, undthis.name
ist null.Verfolgen Sie, wo diese Werte eingestellt werden sollen
Wo ist
this.name
eingestellt? In dersetName(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
setName
verhindern, dass sie auf null gesetzt wird):Entweder die Methode
print
oderprintString
kann nach null suchen , zum Beispiel:Oder Sie können die Klasse so gestalten, dass sie
name
immer einen Wert ungleich Null hat :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 ).
quelle
Frage: Was verursacht a
NullPointerException
(NPE)?Wie Sie wissen sollten, sind Java - Typen unterteilt primitive Typen (
boolean
,int
usw.) und Referenztypen . Mit Referenztypen in Java können Sie den speziellen Wert verwendennull
, mit dem Java "kein Objekt" sagt.A
NullPointerException
wird zur Laufzeit ausgelöst, wenn Ihr Programm versucht, anull
so zu verwenden, als wäre es eine echte Referenz. Zum Beispiel, wenn Sie dies schreiben:Die Anweisung mit der Bezeichnung "HERE" versucht, die
length()
Methode für einenull
Referenz auszuführen , und dies löst a ausNullPointerException
.Es gibt viele Möglichkeiten, wie Sie einen
null
Wert verwenden können, der zu a führtNullPointerException
. In der Tat sind die einzigen Dinge, die Sie mit einem tun können ,null
ohne eine NPE zu verursachen ,:==
oder!=
Operatoren oderinstanceof
.Frage: Wie lese ich den NPE-Stacktrace?
Angenommen, ich kompiliere und führe das obige Programm aus:
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 Standard
javac
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:
Die erste Zeile der Stapelverfolgung enthält eine Reihe von Informationen:
java.lang.NullPointerException
.NullPointerException
ist in dieser Hinsicht ungewöhnlich, da es selten eine Fehlermeldung gibt.Die zweite Zeile ist die wichtigste bei der Diagnose einer NPE.
Dies sagt uns eine Reihe von Dingen:
main
Methode derTest
Klasse waren.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:
Wie kann das eine NPE werfen?
In der Tat gibt es nur einen Weg: Es kann nur passieren, wenn
foo
der Wert hatnull
. Wir versuchen dann, dielength()
Methode auszuführennull
und ... 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.String
Klasse ausgelöst wurde, und Zeile 4 vonTest.java
wä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 .
Jetzt haben wir also zwei "at" -Linien. Der erste ist für diese Zeile:
und der zweite ist für diese Zeile:
Wie könnte das in der ersten Zeile eine NPE werfen? Es gibt zwei Möglichkeiten:
bar
istnull
dannbar[pos]
wird ein NPE werfen.bar[pos]
wirdnull
dann Aufruflength()
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
bar
das? Es ist ein Parameter für dentest
Methodenaufruf, und wenn wir uns ansehen, wietest
aufgerufen wurde, können wir sehen, dass er von derfoo
statischen Variablen stammt. Außerdem können wir deutlich sehen, dass wirfoo
auf einen Wert ungleich Null initialisiert haben. Dies reicht aus, um diese Erklärung vorläufig abzulehnen. (Theoretisch könnte etwas anderes ändernfoo
zunull
... aber das passiert hier nicht.)Was ist also mit unserem zweiten Szenario? Nun, wir können sehen, dass das so
pos
ist1
, das heißt, dasfoo[1]
muss seinnull
. Ist das möglich?Tatsächlich ist es! Und das ist das Problem. Wenn wir so initialisieren:
Wir ordnen a
String[]
mit zwei Elementen zu , die initialisiert werdennull
. Danach haben wir den Inhalt nicht verändertfoo
... sofoo[1]
wird immer nochnull
.quelle
Es ist, als ob Sie versuchen, auf ein Objekt zuzugreifen, das ist
null
. Betrachten Sie das folgende Beispiel: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:
quelle
Eine Nullzeigerausnahme wird ausgelöst, wenn eine Anwendung versucht, Null zu verwenden, wenn ein Objekt erforderlich ist. Diese beinhalten:
null
Objekts.null
Objekts zugreifen oder es ändern .null
als wäre es ein Array.null
als wäre es ein Array.null
als 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
quelle
null
als Ziel einessynchronized
Blocks, 2) Verwenden von anull
als Ziel von aswitch
und Entpackennull
.Ein
null
Zeiger zeigt auf nichts. Wenn Sie einen Zeiger dereferenzierenp
, sagen Sie "Geben Sie mir die Daten an dem in" p "gespeicherten Ort. Wennp
einnull
Zeiger ist, ist der Ort, an dem er gespeichertp
istnowhere
," 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.
quelle
NULL
ist wienull
in Java geschrieben. Und es ist eine Sache, bei der zwischen Groß- und Kleinschreibung unterschieden wird.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
NullPointerException
s überhaupt zu vermeiden .Siehe auch: Eine gute Liste bewährter Methoden
Ich würde hinzufügen, sehr wichtig, den
final
Modifikator gut zu nutzen . Verwenden des Modifikators "final", wann immer dies in Java anwendbar istZusammenfassung:
final
Modifikator, um eine gute Initialisierung zu erzwingen.@NotNull
und@Nullable
if("knownObject".equals(unknownObject)
valueOf()
alstoString()
.StringUtils
MethodenStringUtils.isEmpty(null)
.quelle
@Nullable
wie 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).if (obj==null)
.Wenn es null ist, sollten Sie Code schreiben, um dies ebenfalls zu handhaben.In Java hat alles (außer primitiven Typen) die Form einer Klasse.
Wenn Sie ein Objekt verwenden möchten, haben Sie zwei Phasen:
Beispiel:
Object object;
object = new Object();
Gleiches gilt für das Array-Konzept:
Item item[] = new Item[5];
item[0] = new Item();
Wenn Sie den Initialisierungsabschnitt nicht angeben,
NullPointerException
entsteht der.quelle
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.
Der folgende Code gibt Ihnen eine Nullzeigerausnahme.
Weil Sie verwenden
student
, aber vergessen haben, es wie im richtigen Code unten zu initialisieren:quelle
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
this
Referenzen darauf zugreifen . Nehmen Sie dieses Beispiel:Und an einer anderen Stelle in Ihrem Code:
Dies ist eine wichtige Sache zu wissen - wenn es keine Verweise mehr auf ein Objekt gibt (im obigen Beispiel, wenn
reference
undotherReference
beide 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.quelle
Ein anderes Auftreten von a
NullPointerException
tritt auf, wenn man ein Objektarray deklariert und dann sofort versucht, darin enthaltene Elemente zu dereferenzieren.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 sind
null
.Sie müssen die Elemente im Array initialisieren, bevor Sie auf sie zugreifen oder sie dereferenzieren können.
quelle
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.