Antworten:
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?
int a=bKann eine NPE auslösen, wenn b eine ist Integer. Es gibt Fälle, in denen das Debuggen verwirrend ist.
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?)
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.)
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?
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.
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() .
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:
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 ).
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 ,:
==oder !=Operatoren oder instanceof.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:
java.lang.NullPointerException.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:
mainMethode der TestKlasse 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 ...
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:
barist nulldann bar[pos]wird ein NPE werfen.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.
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
Eine Nullzeigerausnahme wird ausgelöst, wenn eine Anwendung versucht, Null zu verwenden, wenn ein Objekt erforderlich ist. Diese beinhalten:
nullObjekts.nullObjekts zugreifen oder es ändern .nullals wäre es ein Array.nullals wäre es ein Array.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
nullals Ziel eines synchronizedBlocks, 2) Verwenden von a nullals Ziel von a switchund Entpacken null.
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.
NULList wie nullin 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 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:
finalModifikator, um eine gute Initialisierung zu erzwingen.@NotNull und@Nullableif("knownObject".equals(unknownObject)valueOf() als toString().StringUtils Methoden StringUtils.isEmpty(null).@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).
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, NullPointerExceptionentsteht der.
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");
}
}
}
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.
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));
}
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.