Warum löst String.valueOf (null) eine NullPointerException aus?


127

Gemäß der Dokumentation gibt die Methode String.valueOf(Object obj)Folgendes zurück:

Wenn das Argument ist null, dann ist eine Zeichenfolge gleich "null"; Andernfalls wird der Wert von obj.toString()zurückgegeben.

Aber wie kommt es, wenn ich das versuche:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

wirft es stattdessen NPE? (Probieren Sie es selbst aus, wenn Sie nicht glauben!)

    Ausnahme im Thread "main" java.lang.NullPointerException
    at java.lang.String. (Unbekannte Quelle)
    at java.lang.String.valueOf (Unbekannte Quelle)

Wie kommt es, dass das passiert? Lügt mich die Dokumentation an? Ist das ein großer Fehler in Java?

Antworten:


201

Das Problem ist, dass die String.valueOfMethode überladen ist :

Die Java Specification Language schreibt vor, dass in solchen Fällen die spezifischste Überlastung ausgewählt wird:

JLS 15.12.2.5 Auswahl der spezifischsten Methode

Wenn auf mehr als eine Mitgliedsmethode zugegriffen werden kann und auf einen Methodenaufruf anwendbar ist, muss eine ausgewählt werden, um den Deskriptor für den Versand der Laufzeitmethode bereitzustellen. Die Programmiersprache Java verwendet die Regel, dass die spezifischste Methode ausgewählt wird.

A char[] ist-ein Object , aber nicht alles Object ist-a char[] . Daher char[]ist die Überladung in diesem Fall spezifischer als Objectund wie in der Java-Sprache angegeben String.valueOf(char[]).

String.valueOf(char[])erwartet, dass das Array nicht ist null, und da nulles in diesem Fall angegeben ist, wird es dann geworfen NullPointerException.

Die einfache "Lösung" besteht darin, das nullexplizit Objectwie folgt umzuwandeln:

System.out.println(String.valueOf((Object) null));
// prints "null"

Verwandte Fragen


Moral der Geschichte

Es gibt mehrere wichtige:

  • Effektive Java 2nd Edition, Punkt 41: Verwenden Sie Überladung mit Bedacht
    • Nur weil Sie überladen können, heißt das nicht, dass Sie es jedes Mal tun sollten
    • Sie können Verwirrung stiften (insbesondere wenn die Methoden völlig unterschiedliche Dinge tun)
  • Mit einer guten IDE können Sie überprüfen, welche Überladung beim Kompilieren ausgewählt ist
    • Mit Eclipse können Sie mit der Maus über den obigen Ausdruck fahren und sehen, dass tatsächlich die valueOf(char[])Überladung ausgewählt ist!
  • Manchmal möchten Sie explizit besetzen null(Beispiele folgen)

Siehe auch


Beim Casting null

Es gibt mindestens zwei Situationen, in denen eine explizite Umwandlung nullin einen bestimmten Referenztyp erforderlich ist:

  • Überladung auswählen (wie im obigen Beispiel angegeben)
  • Zu geben nullals ein einziges Argument an einen Vararg Parameter

Ein einfaches Beispiel für Letzteres ist das Folgende:

static void vararg(Object... os) {
    System.out.println(os.length);
}

Dann können wir folgendes haben:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

Siehe auch

Verwandte Fragen


5
Ein weiterer Vorschlag: Wenn Sie eine Methode überladen und ein Argument für zwei Überladungen aufgerufen werden kann (wie nullin diesem Fall), stellen Sie sicher, dass beide Überladungen in Bezug auf diesen Wert gleich sind!
Joachim Sauer

3
@ Joachim: Ich habe gerade den Artikel gelesen und war angenehm überrascht, dass diese beiden Methoden explizit diskutiert wurden! Bloch ging noch einen Schritt weiter und behauptete, dass seitdem String.valueOf(Object)und valueOf(char[])sowieso völlig andere Dinge (unabhängig davon nulloder nicht), dass sie vielleicht gar nicht überlastet sein sollten.
Polygenelubricants

Haben Sie eine Frage ... Wenn Sie eine Methode haben, die ein Objekt zurückgibt, ist die Anweisung return null;genau die gleiche wie return (Object) null;?
user972276

17

Das Problem ist, dass Sie anrufen String.valueOf(char[])und nicht String.valueOf(Object) .

Der Grund dafür ist, dass Java immer die spezifischste Version einer überladenen Methode auswählt, die mit den angegebenen Parametern arbeitet. nullist ein gültiger Wert für einen ObjectParameter, aber auch ein gültiger Wert für einen char[]Parameter.

Damit Java die ObjectVersion verwendet, übergeben Sie sie entweder nullüber eine Variable oder geben Sie eine explizite Umwandlung in Object an:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));

5

Für diesen Weg wurde bereits 2003 ein Fehler mit der Nummer 4867608 eingereicht, der mit dieser Erklärung als "nicht behebbar" behoben wurde.

Wir können dies aufgrund von Kompatibilitätsbeschränkungen nicht ändern. Beachten Sie, dass die öffentliche statische String valueOf-Methode (char data []) aufgerufen wird und das Ersetzen von "null" für null-Argumente nicht erwähnt wird.

@ ###. ### 2003-05-23


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.