Frage

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

Welche Methoden / Geräte verwendet werden kann, um die Ursache zu ermitteln, so dass Sie die Ausnahme beenden Sie das Programm von verursacht vorzeitig zu beenden?

War es hilfreich?

Lösung

Wenn Sie eine Referenzvariable deklarieren (das heißt ein Objekt) Sie wirklich einen Zeiger auf ein Objekt zu schaffen. Betrachten Sie den folgenden Code, in dem Sie eine Variable vom Urtyp int deklarieren:

int x;
x = 10;

In diesem Beispiel wird die Variable x ist ein int und Java wird initialisieren es für Sie 0. Wenn Sie den Wert von 10 in der zweiten Zeile zuweisen, Ihr Wert von 10 wird in den Speicherplatz geschrieben von x bezeichnet.

Aber, wenn Sie versuchen, einen Verweis zu erklären type , etwas anderes passiert. Nehmen Sie den folgenden Code ein:

Integer num;
num = new Integer(10);

Die erste Zeile deklariert eine Variable num genannt, aber es eigentlich keinen Grundwert noch enthalten. Stattdessen enthält sie einen Zeiger (weil der Typ, der eine Referenz Integer Typ ist). Da Sie noch nicht gesagt, was zu zeigen, setzt Java es null, was bedeutet, " Ich deutete auf nichts ".

In der zweiten Zeile wird das Schlüsselwort verwendet new zu instanziiert (oder erstellen) ein Objekt des Typs Integer und die Zeigervariable num zu diesem Integer Objekt zugeordnet.

Die NullPointerException tritt auf, wenn Sie eine Variable deklarieren, aber nicht schaffen, ein Objekt. So sind Sie zeigt auf etwas, das nicht wirklich existiert.

Wenn Sie zu dereferenzieren num versuchen, bevor Sie das Objekt erstellen erhalten Sie einen NullPointerException. In den trivialen Fällen wird der Compiler das Problem fangen und lassen Sie wissen, dass „num may not have been initialized“, aber manchmal können Sie Code schreiben, der nicht direkt das Objekt nicht erstellen.

Zum Beispiel können Sie eine Methode wie folgt:

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

In diesem Fall, erstellen Sie das Objekt nicht obj, sondern vielmehr davon aus, dass es erstellt wurde, bevor die doSomething() Methode aufgerufen wurde. Beachten Sie, es ist möglich, das Verfahren so zu nennen:

doSomething(null);

In diesem Fall ist obj null. Wenn das Verfahren soll etwas zum übergebene Objekt tun, ist es angebracht, die NullPointerException zu werfen, weil es ein Programmierer Fehler ist und der Programmierer, dass die Informationen für Debugging-Zwecke benötigen.

Alternativ kann es Fälle geben, in denen der Zweck des Verfahrens nicht nur auf dem übergebenen Objekt zu bedienen ist und daher ein Nullparameter akzeptabel sein kann. In diesem Fall müssten Sie für eine null Parameter und verhalten sich anders zu überprüfen. Sie sollten auch diese in der Dokumentation erklären. Zum Beispiel doSomething() 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 Wie die Ausnahme lokalisieren und verursachen mit Stack-Trace

Andere Tipps

NullPointerExceptions sind Ausnahmen, die auftreten, wenn Sie versuchen, eine Referenz zu verwenden, die im Speicher (null) zu keinem Ort verweist, als ob es ein Objekt wurde verweisen. Aufruf einer Methode auf einem NULL-Verweis oder versuchen, ein Feld eines NULL-Verweis für den Zugriff auf eine NullPointerException auslösen. Dies sind die häufigsten, aber auch andere Möglichkeiten, auf der NullPointerException javadoc Seite.

Wahrscheinlich der schnellste Beispiel Code, den ich einfiel eine NullPointerException zu erläutern sei:

public class Example {

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

}

In der ersten Zeile innerhalb main, bin ich Einstellung explizit die Object Referenz obj gleich null. Das bedeutet, ich habe eine Referenz, aber es zeigt nicht auf ein beliebiges Objekt. Danach habe ich versuchen, die Referenz zu behandeln, als ob es durch den Aufruf einer Methode auf es auf ein Objekt verweist. Dies führt zu einem NullPointerException, weil es kein Code ist in der Lage auszuführen, die die Referenz verweist.

(Dies ist eine Form, aber ich denke, es trägt zu erwähnen. Eine Referenz, die auf null Punkte ist nicht das gleiche wie ein C-Zeiger, der auf eine ungültige Speicherstelle weist ein Null-Zeiger ist buchstäblich zeigt nicht überall , die auf subtile Weise anders ist zu einer Stelle als Hinweis, das ungültig sein geschieht.)

Was ist ein Nullpointer?

Ein guter Anfang ist die JavaDocs . Sie haben dies behandelt:

  

Geworfen, wenn eine Anwendung versucht, in einem Fall null zu verwenden, wo ein   Objekt erforderlich ist. Dazu gehören:

     
      
  • Der Aufruf der Instanzmethode eines Null-Objekt.
  •   
  • Zugriff oder das Feld eines Null-Objekt zu ändern.
  •   
  • Nehmen Sie die Länge von null, als ob es ein Array waren.
  •   
  • Zugriff oder die Schlitze null Modifizieren, als ob es ein Array waren.
  •   
  • Werfen null, als ob es ein Throwable Wert war.
  •   
     

Die Anträge sollten Instanzen dieser Klasse werfen andere, um anzuzeigen,   illegale Verwendungen des Null-Objekt.

Es ist auch der Fall, dass, wenn Sie versuchen, einen NULL-Verweis mit synchronized zu verwenden, die auch diese Ausnahme werfen, pro der JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
     
      
  • Andernfalls, wenn der Wert des Ausdrucks Null ist, wird ein NullPointerException geworfen.
  •   

Wie kann ich das Problem beheben?

So haben Sie eine NullPointerException haben. Wie sehen Sie das Problem beheben? Nehmen wir ein einfaches Beispiel nehmen, die eine NullPointerException wirft:

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 NULL-Werte

Der erste Schritt ist das Identifizieren genau welche Werte verursachen die Ausnahme . Dafür brauchen wir einige Debug zu tun. Es ist wichtig, ein stacktrace , lesen zu lernen. Dies wird Ihnen zeigen, 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 auf der Leitung geworfen 13 (in der printString Methode). Schauen Sie sich die Linie und prüfen Sie, welche Werte sind null durch Hinzufügen Logging-Anweisungen oder Debugger verwenden. Wir finden heraus, dass s null ist, und auf die length Aufruf der Methode wirft die Ausnahme. Wir können sehen, dass das Programm nicht mehr die Ausnahme werfen, wenn s.length() aus dem Verfahren entfernt wird.

Trace, wo diese Werte stammen aus

Als nächstes Check wo dieser Wert herkommt. Indem Sie den Anrufer des Verfahrens sehen wir, dass s mit printString(name) im print() Verfahren eingeleitet, und this.name ist null.

Trace wo sollten diese Werte eingestellt werden

Wo ist this.name Satz? Im setName(String) Verfahren. Mit etwas mehr Debuggen, können wir sehen, dass diese Methode nicht aufgerufen wird. Wenn die Methode aufgerufen wurde, stellen Sie sicher, dass die um zu prüfen, , dass diese Methoden genannt werden, und die Set-Methode ist nicht genannt nach der Druckmethode.

Das ist genug, um uns um eine Lösung zu geben: einen Anruf vor dem Aufruf printer.setName() printer.print() hinzufügen

.

Andere Korrekturen

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

private String name = "";

Entweder die print oder printString Methode kann für null überprüfen , zum Beispiel:

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

Sie können auch die Klasse so auszugestalten, dass name immer einen Nicht-Null-Wert :

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 immer noch nicht das Problem finden

Wenn Sie das Problem zu debuggen, versucht, und haben immer noch keine Lösung, können Sie eine Frage, um weitere Hilfe zu veröffentlichen, aber stellen Sie sicher zu schließen, was Sie bisher versucht haben. Zumindest sind die Stacktrace in der Frage, und kennzeichnen die wichtigen Zeilennummern im Code. Versuchen Sie auch, den Code zu vereinfachen ersten (siehe SSCCE ).

Frage: Was bewirkt ein NullPointerException (NPE)

?

Wie Sie wissen sollten, sind Java-Typen unterteilt in primitive Typen (boolean, int, etc.) und Referenztypen . Referenztypen in Java ermöglicht es Ihnen, den besonderen Wert null zu verwenden, das ist die Java-Weg „kein Objekt“ zu sagen.

Ein NullPointerException wird zur Laufzeit geworfen, wenn Ihr Programm versucht, eine null zu verwenden, als ob es eine echte Referenz war. Zum Beispiel, wenn Sie schreiben diese:

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

die Aussage mit „HIER“ wird die length() Methode auf einer null Referenz, um zu versuchen zu laufen, und dies wird ein NullPointerException werfen.

Es gibt viele Möglichkeiten, wie Sie einen null Wert verwenden könnte, die in einem NullPointerException führen. In der Tat, dass die einzigen Dinge, die Sie können zu tun mit einem null ohne eine NPE zu verursachen, sind:

  • Zuweisen zu einem Referenzgröße oder diese von einer Referenzgröße lesen,
  • Zuweisen zu einem Array-Elemente oder aus einem Array-Elemente gelesen werden (vorausgesetzt, dass Array Referenz selbst nicht null!),
  • es als Parameter übergeben oder als Ergebnis zurück, oder
  • test es die == oder != Operatoren oder instanceof.

Frage: Wie kann ich die NPE stacktrace lesen

Angenommen

, dass ich kompilieren und starten Sie das Programm über:

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

Erste Beobachtung: die Kompilierung erfolgreich ist! Das Problem in dem Programm ist nicht ein Übersetzungsfehler. Es ist ein Laufzeit Fehler. (Einige IDEs kann Ihr Programm warnen immer eine Ausnahme werfen ... aber der Standard javac Compiler nicht.)

Zweite Beobachtung: Wenn ich das Programm ausführen, es gibt zwei Linien von „gobbledy-Gook“. FALSCH !! Das ist nicht gobbledy-gook. Es ist ein stacktrace ... und es bietet wichtige Informationen , die Sie den Fehler in Ihrem Code aufzuspüren helfen, wenn Sie die Zeit nehmen, sie sorgfältig zu lesen.

also lasst uns schauen, was es sagt:

Exception in thread "main" java.lang.NullPointerException

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

  • Es sagt Ihnen, den Namen des Java-Thread, in dem die Ausnahme ausgelöst wurde. Für ein einfaches Programm mit einem Thread (wie diese), wird es „main“ sein. Lassen Sie uns weitermachen ...
  • Es sagt Ihnen, den vollständigen Namen der Ausnahme, die ausgelöst wurde; das heißt java.lang.NullPointerException.
  • Wenn die Ausnahme eine zugehörige Fehlermeldung hat, das wird ausgegeben, nachdem Ausnahme Name sein. NullPointerException ist ungewöhnlich, in dieser Hinsicht, weil es selten eine Fehlermeldung hat.

Die zweite Zeile ist das wichtigste eine NPE bei der Diagnose.

at Test.main(Test.java:4)

Dies sagt uns, eine Reihe von Dingen:

  • "bei Test.main" sagt, dass wir in der main Methode der Test Klasse sind.
  • „Test.java:4“ gibt die Quelle Dateinamen der Klasse, und es sagt uns, dass die Aussage, wo diese in Zeile aufgetreten ist 4 der Datei.

Wenn Sie die Zeilen in der Datei oben zählen, Zeile 4 ist die eine, die ich mit dem „HERE“ Kommentar gekennzeichnet.

Beachten Sie, dass in einem komplizierteren Beispiel wird es viele Linien in dem NPE-Stack-Trace sein. Aber Sie können sicher sein, dass die zweite Zeile (die erste „auf“ Linie) werden Ihnen sagen, wo der NPE geworfen wurde 1 .

Kurzschluss in dem Stack-Trace wird uns sagen eindeutig, welche Aussage des Programms der NPE geworfen hat.

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

Frage: Wie kann ich die Ursache für die NPE Ausnahme in meinem Code aufzuspüren

Dies ist der schwierige Teil. Die kurze Antwort ist logische Folgerung zu den Beweismittel durch den Stack-Trace, der Quellcode und die entsprechenden API-Dokumentation.

vorgesehen anzuwenden

Lassen Sie sich mit dem einfachen Beispiel illustriert (siehe oben) zuerst. Wir beginnen am l suchenine, dass der Stack-Trace hat uns gesagt, wo der NPE passiert:

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

Wie kann das eine NPE werfen?

In der Tat gibt es nur einen Weg: es kann nur geschehen, wenn foo den Wert null hat. Wir haben dann versuchen, die length() Methode auf null laufen und .... BANG!

Aber (höre ich Sie sagen), was, wenn die NPE in dem length() Methodenaufruf ausgelöst wurde?

Nun, wenn das passiert, würde die Stack-Trace anders aussehen. Die erste „auf“ Linie würde sagen, dass die Ausnahme in irgendeiner Zeile in der java.lang.String Klasse geworfen wurde, und Linie 4 von Test.java wäre die zweite „auf“ Linie sein.

Also, wo ist die null gekommen? In diesem Fall ist es offensichtlich, und es ist offensichtlich, was wir es beheben tun müssen. (Vergeben Sie einen Nicht-Null-Wert zu foo.)

OK, so wollen sie versuchen, ein etwas kniffliges Beispiel. Dies wird einige erfordern logische Deduktion .

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

So, jetzt haben wir zwei „auf“ Linien. Die erste ist für diese Linie:

return args[pos].length();

und die zweite ist für diese Linie:

int length = test(foo, 1);

Mit Blick auf der ersten Zeile, wie das eine NPE werfen könnte? Es gibt zwei Möglichkeiten:

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

Als nächstes müssen wir, um herauszufinden, welche dieser Szenarien erklärt, was tatsächlich geschieht. Wir werden zunächst die erste Erkundung:

Wo kommt bar kommen aus? Es ist ein Parameter an den test Methodenaufruf, und wenn wir uns anschauen, wie test genannt wurde, können wir sehen, dass es von den foo statischen Variablen kommt. Darüber hinaus können wir deutlich sehen, dass wir foo auf einen Wert ungleich Null initialisiert. Das reicht aus, um versuchsweise diese Erklärung zu entlassen. (In der Theorie etwas anderes könnte Veränderung foo null ... aber das geschieht nicht hier.)

Und was ist unser zweites Szenario? Nun, wir können sehen, dass pos 1 ist, so bedeutet das, dass foo[1] null werden müssen. Ist das möglich?

Tatsächlich ist es! Und das ist das Problem. Wenn wir initialisieren wie folgt aus:

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

Wir weisen Sie einen String[] mit zwei Elementen , die null initialisiert . Danach haben wir den Inhalt foo nicht geändert ... so foo[1] noch null werden.

Es ist wie Sie versuchen, auf ein Objekt zuzugreifen, die null ist. Betrachten wir folgende Beispiel:

TypeA objA;

Zu diesem Zeitpunkt müssen Sie nur noch erklärt , um dieses Objekt aber nicht initialisiert oder instanziiert . Und wenn Sie versuchen, in das jede Eigenschaft oder Methode zuzugreifen, wird es NullPointerException werfen, die Sinn macht.

Sehen Sie das folgende Beispiel auch:

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

Eine Null-Zeiger-Ausnahme wird ausgelöst, wenn eine Anwendung in einem Fall null zu verwenden versucht, in dem ein Objekt erforderlich ist. Dazu gehören:

  1. Aufruf der Instanzmethode eines null Objekt.
  2. Zugriff oder das Feld eines null Objekt zu ändern.
  3. Nehmen Sie die Länge von null, als ob es ein Array waren.
  4. Zugriff oder die Schlitze null modifizieren, als ob es ein Array waren.
  5. Werfen null, als ob es ein Throwable Wert war.

Die Anträge sollten Instanzen dieser Klasse werfen, um andere illegale Verwendungen des null Objekts.

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

Ein null Zeiger ist eine, die nirgendwo verweist. Wenn Sie dereferenzieren einen Zeiger p, Sie sagen, „geben Sie mir die Daten an der Stelle in gespeichert‚p‘. Wenn p ein null Zeiger gespeicherte Position in p nowhere ist, da sagst du:“ Gib mir die Daten an der Stelle ‚nirgendwo‘“. Offensichtlich kann sie dies nicht tun, so dass es eine null pointer exception wirft.

In der Regel ist es weil etwas nicht richtig initialisiert wurde.

Viele Erklärungen sind bereits zu erklären, wie es geschieht und wie es zu beheben, aber Sie sollten auch folgen Best Practices NullPointerException überhaupt zu vermeiden.

Siehe auch: eine gute Liste bewährte Praktiken

Ich möchte hinzufügen, sehr wichtig, eine gute Nutzung des final Modifikator machen. Mit dem "final" Modifikator, wann immer anwendbar in Java

Zusammenfassung:

  1. Verwenden Sie den final Modifikator gute Initialisierung zu erzwingen.
  2. Vermeiden Sie null in Methoden zurückkehren, zum Beispiel leere Sammlungen zurückkehrt, wenn anwendbar.
  3. Verwenden Sie Anmerkungen @NotNull und @Nullable
  4. Fehler schnell und Verwendung behauptet Ausbreitung von null Gegenstände durch die gesamte Anwendung zu vermeiden, wenn sie nicht null sein sollte.
  5. Verwenden Sie gleich mit einem bekannten Objekt zuerst: if("knownObject".equals(unknownObject)
  6. Bevorzugen valueOf() über toString ().
  7. Verwenden Sie null sichere StringUtils Methoden StringUtils.isEmpty(null).

Eine Null-Zeiger-Ausnahme ist ein Indikator dafür, dass Sie ein Objekt verwenden, ohne es zu initialisieren.

Zum Beispiel ist eine Student-Klasse, die es in unserem Code verwenden wird.

public class Student {

    private int id;

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

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

Der Code unten gibt Ihnen eine Null-Zeiger-Ausnahme.

public class School {

    Student student;

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

Weil Sie verwenden student, aber Sie vergessen haben, es wie in initialisieren die korrekter Code unten dargestellt:

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 alles (ohne Urtyp) in Form einer Klasse.

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

  1. Erklären
  2. Initialisierung

Beispiel:

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

Das Gleiche gilt für das Array-Konzept:

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

Wenn Sie nicht den Initialisierungsabschnitt geben dann die NullPointerException entstehen.

In Java alle Variablen Sie deklarieren sind eigentlich „Referenzen“ auf die Objekte (oder Primitiven) und nicht die Objekte selbst.

Wenn Sie versuchen, ein Objekt Methode auszuführen, fragt die Referenz das lebende Objekt, das Verfahren auszuführen. Aber wenn die Referenz verweist auf NULL (nichts, null, nichtig, nada), dann gibt es keine Möglichkeit, die Methode ausgeführt wird. Dann wird die Laufzeit lassen Sie uns das wissen durch eine Nullpointer werfen.

Ihre Referenz "zeigen" zu null, also "Null -> Pointer".

Das Objekt wohnt in der VM Speicherplatz und die einzige Möglichkeit für den Zugriff ist this Referenzen verwenden. 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 einem anderen Ort 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 weiteren Verweise auf ein Objekt (im Beispiel oben, wenn reference und beide otherReference Punkt auf null) sind dann das Objekt „nicht erreichbar“. Es gibt keine Art, wie wir mit ihm arbeiten können, so ist dieses Objekt bereit Müll gesammelt zu werden, und irgendwann wird die VM die von diesem Objekt verwendeten Speicher freizugeben und wird ein weiteres zuordnen.

Ein weiteres Auftreten eines NullPointerException tritt auf, wenn man ein Objekt Array erklärt, versucht dann sofort zu dereferenzieren Elementen innerhalb davon.

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

Diese besondere NPE kann vermieden werden, wenn der Vergleich der Reihenfolge umgekehrt ist; nämlich verwendet .equals auf einen garantiert nicht-Null-Objekt.

Alle Elemente innerhalb eines Arrays

scroll top