Perché String.valueOf (null) genera una NullPointerException?


127

secondo la documentazione, il metodo String.valueOf(Object obj)restituisce:

se l'argomento è null, allora una stringa uguale a "null"; in caso contrario, obj.toString()viene restituito il valore di .

Ma come mai quando provo a fare questo:

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

lancia NPE invece? (provalo tu stesso se non ci credi!)

    Eccezione nel thread "main" java.lang.NullPointerException
    at java.lang.String. (fonte sconosciuta)
    at java.lang.String.valueOf (fonte sconosciuta)

Come mai sta succedendo questo? La documentazione mi sta mentendo? È un bug importante in Java?

Risposte:


201

Il problema è che il String.valueOfmetodo è sovraccarico :

Java Specification Language richiede che in questo tipo di casi venga scelto il sovraccarico più specifico :

JLS 15.12.2.5 Scelta del metodo più specifico

Se più di un metodo membro è sia accessibile sia applicabile all'invocazione di un metodo, è necessario sceglierne uno per fornire il descrittore per l'invio del metodo di runtime. Il linguaggio di programmazione Java utilizza la regola che viene scelto il metodo più specifico .

A char[] is-an Object , ma non tutto Object è-a char[] . Pertanto, char[]è più specifico di Object, e come specificato dal linguaggio Java, String.valueOf(char[])in questo caso viene scelto il sovraccarico.

String.valueOf(char[])si aspetta che l'array non sia null, e poiché nullin questo caso viene fornito, viene generato NullPointerException.

La semplice "correzione" è di lanciare nullesplicitamente Objectcome segue:

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

Domande correlate


Morale della storia

Ce ne sono alcuni importanti:

  • Efficace Java 2nd Edition, Item 41: utilizzare l'overloading con giudizio
    • Solo perché puoi sovraccaricare, non significa che dovresti sempre
    • Possono causare confusione (specialmente se i metodi fanno cose molto diverse)
  • Usando un buon IDE, puoi verificare quale sovraccarico è selezionato al momento della compilazione
    • Con Eclipse, puoi passare con il mouse sull'espressione sopra e vedere che effettivamentevalueOf(char[]) è selezionato il sovraccarico!
  • A volte vuoi esplicitamente trasmettere null(esempi da seguire)

Guarda anche


Al casting null

Esistono almeno due situazioni in cui nullè necessario eseguire il cast esplicito su un tipo di riferimento specifico:

  • Per selezionare il sovraccarico (come indicato nell'esempio sopra)
  • Da dare nullcome singolo argomento a un parametro vararg

Un semplice esempio di quest'ultimo è il seguente:

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

Quindi, possiamo avere quanto segue:

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

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

Guarda anche

Domande correlate


5
Un altro suggerimento: quando sovraccarichi un metodo e un argomento può essere chiamato su due sovraccarichi (come nullin questo caso), assicurati che entrambi i sovraccarichi si comportino allo stesso modo rispetto a quel valore!
Joachim Sauer,

3
@Joachim: ho appena letto l'articolo e sono rimasto piacevolmente sorpreso di scoprire che questi due metodi sono stati esplicitamente discussi! Bloch fece un ulteriore passo avanti e affermò che da allora String.valueOf(Object)e valueOf(char[])facendo comunque cose completamente diverse (indipendentemente dal fatto nullo no) che forse non avrebbero dovuto essere sovraccarichi in primo luogo.
poligenelubrificanti,

Hai una domanda ... se hai un metodo che restituisce un oggetto, l'istruzione return null;sarebbe esattamente la stessa cosa di return (Object) null;?
user972276

17

Il problema è che stai chiamando String.valueOf(char[])e non String.valueOf(Object) .

La ragione di ciò è che Java sceglierà sempre la versione più specifica di un metodo sovraccarico che funziona con i parametri forniti. nullè un valore valido per un Objectparametro, ma è anche un valore valido per un char[]parametro.

Per fare in modo che Java utilizzi la Objectversione, passare nulltramite una variabile o specificare un cast esplicito su Object:

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

5

Un bug, numerato 4867608, è stato archiviato in questo modo nel 2003, che è stato risolto come "non risolverà" con questa spiegazione.

Non possiamo cambiarlo a causa di vincoli di compatibilità. Si noti che è il metodo String valueOf (char data []) statico pubblico che finisce per essere invocato e non menziona la sostituzione di "null" per argomenti null.

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


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.