Der häufigste Fehler in Java
Eine NullPointerException (alle nennen sie NPE) tritt auf, wenn du versuchst, eine Referenz, die auf nichts zeigt -null-, so zu verwenden, als würde sie auf ein echtes Objekt zeigen. Java-Variablen eines Objekttyps enthalten entweder ein Objekt oder null, den Wert für „hier ist kein Objekt". In dem Moment, in dem du null bittest, etwas zu tun - eine Methode darauf aufzurufen, eines seiner Felder zu lesen, darauf zu indizieren -, gibt es nichts, worauf man wirken könnte, also wirft die JVM eine Exception.
Anders als try-catch, zu dem du auf der vorigen Seite greifst, um erwartete Fehler zu behandeln, ist eine NPE fast immer schlicht ein Bug. Das Ziel dieser Seite ist nicht, sie abzufangen, sondern zu verstehen, warum sie auftreten, und Code zu schreiben, der sie gar nicht erst erzeugt.
Es gibt keinen String, auf dem length() laufen könnte, also stoppt das Programm mit einer NullPointerException.
Die Meldung lesen
Seit Java 14 sagt dir die Meldung genau, was null war - das nennt man Helpful NullPointerException (hilfreiche NPE). Lies sie, bevor du irgendetwas änderst:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
at Main.main(Main.java:4)
Zwei Teile sind wichtig. Cannot invoke "String.length()" ist die fehlgeschlagene Operation, und because "name" is null benennt den Schuldigen. Die Zeile at Main.main(Main.java:4) ist der Stacktrace, der auf die genaue Zeile zeigt. Die Lösung ist also nicht „Zeile 4 in ein try einpacken" - sondern „herausfinden, warum name in Zeile 4 null ist". Fast immer steckt der Bug irgendwo weiter oben, dort, wo der Wert hätte zugewiesen werden sollen und es nicht wurde.
Die Wege, eine auszulösen
NPEs entstehen aus einer Handvoll Operationen, allesamt Variationen von „null anfassen":
Map-Suchen sind eine klassische Quelle: get liefert null, wenn der Schlüssel fehlt, und die NPE taucht oft erst Zeilen später auf, wenn du diesen Wert endlich verwendest. Das Unboxing ist das Tückische - einen null-Integer einem int zuzuweisen, wirft eine Exception, weil es keine Zahl zum Kopieren gibt.
Mit einer Null-Prüfung absichern
Die einfachste Verteidigung ist ein if, das bestätigt, dass eine Referenz nicht null ist, bevor du sie verwendest:
Wenn du eine Variable mit einem konstanten String vergleichst, stell die Konstante voran - "yes".equals(answer) statt answer.equals("yes"). Ist answer null, liefert die erste Form gelassen false, während die zweite eine Exception wirft.
Schnell scheitern mit Objects.requireNonNull
Überall null-Prüfungen zu verstreuen wird unübersichtlich. Wenn ein Wert niemals null sein sollte - wie ein Konstruktorargument -, validiere ihn an der Grenze mit Objects.requireNonNull. Es wirft sofort, mit einer klaren Meldung, an der Stelle, an der der schlechte Wert ankommt, statt erst später tief in deinem Code:
Diese Gewohnheit des „schnellen Scheiterns" verwandelt eine vage NPE 200 Zeilen entfernt in eine präzise Beschwerde an der Quelle. Die Exception hier abzufangen, dient nur dazu, die Meldung zu zeigen - in echtem Code würdest du sie hochsprudeln lassen, damit der Bug behoben wird.
Nulls von vornherein vermeiden
Die beste NPE ist die, die nie auftreten kann, weil es kein null gibt, auf das man treffen könnte. Ein paar Gewohnheiten bringen viel:
- Gib eine leere Collection oder Zeichenkette zurück, niemals
null.Collections.emptyList()und""lassen sich gefahrlos durchlaufen und Methoden darauf aufrufen. - Verwende
getOrDefaultauf Maps, damit eine fehlgeschlagene Suche einen echten Wert stattnullliefert. - Initialisiere Felder bei der Deklaration, statt sie bis „später" auf
nullzu lassen.
Wenn ein Wert tatsächlich optional ist - eine Suche, die legitim nichts finden kann -, bietet Java Optional, einen Container, der den Aufrufer zwingt, den Fall „abwesend" zu behandeln, statt stillschweigend ein null zurückzugeben. Das ist das verwandte Konzept, das du als Nächstes lesen solltest, wenn du diese Lücken vollständig aus dem Design deiner APIs verbannen willst.
Zusammenfassung
Eine NullPointerException ist Javas Art, dir zu sagen, dass du eine Referenz, die null enthielt, so verwendet hast, als enthielte sie ein Objekt. Die Lösung besteht selten darin, sie abzufangen - es geht darum, die hilfreiche Meldung zu lesen, zurückzuverfolgen, wo der Wert hätte gesetzt werden sollen, und entweder zu garantieren, dass er nicht null ist, oder die Stelle abzusichern, an der du ihn verwendest. Stütze dich auf Objects.requireNonNull, um an Grenzen schnell zu scheitern, bevorzuge leere Werte und getOrDefault gegenüber null, und greife zu Optional, wenn Abwesenheit ein echtes, erwartetes Ergebnis ist. Beherrsche diese Denkweise, und der häufigste Fehler in Java wird zu einem der seltensten in deinem eigenen Code.
Häufig gestellte Fragen
Was verursacht eine NullPointerException in Java?
Sie tritt auf, wenn du eine Referenz, die auf null zeigt, so verwendest, als würde sie auf ein echtes Objekt zeigen - zum Beispiel beim Aufruf einer Methode (name.length()), beim Lesen eines Felds, beim Zugriff auf ein Array-Element oder beim Entpacken (Unboxing) eines null-Integer. Die Variable enthält kein Objekt, also gibt es nichts, worauf man wirken könnte, und die JVM wirft eine NullPointerException.
Wie behebt man eine NullPointerException in Java?
Lies die Meldung - seit Java 14 nennt sie genau, was null war (z. B. "Cannot invoke "String.length()" because "name" is null"). Verfolge dann, warum diese Variable null ist: eine fehlende Initialisierung, eine Methode, die null zurückgab, oder eine Map-Suche, die nichts fand. Behebe die Ursache, sodass der Wert nie null ist, oder sichere die Verwendung mit einer null-Prüfung, Objects.requireNonNull oder Optional ab.
Ist es besser, auf null zu prüfen oder eine NullPointerException abzufangen?
Prüfe auf null. Eine NullPointerException signalisiert einen Fehler in deiner Logik, keinen erwarteten Zustand, daher solltest du sie verhindern statt sie abzufangen. Sie abzufangen verschleiert, wo das eigentliche Problem liegt. Reserviere try/catch für wirklich außergewöhnliche Situationen wie E/A-Fehler.