¿Por qué String.valueOf (null) arroja una NullPointerException?

127

De acuerdo con la documentación, el método String.valueOf(Object obj)devuelve:

si el argumento es null, entonces una cadena igual a "null"; de lo contrario, obj.toString()se devuelve el valor de .

Pero, ¿cómo es que cuando trato de hacer esto?

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

arroja NPE en su lugar? (¡pruébalo tú mismo si no crees!)

    Excepción en el hilo "main" java.lang.NullPointerException
    en java.lang.String. (Fuente desconocida)
    en java.lang.String.valueOf (fuente desconocida)

¿Cómo es que esto está sucediendo? ¿Me está mintiendo la documentación? ¿Es este un error importante en Java?

usuario282886
fuente

Respuestas:

201

El problema es que el String.valueOfmétodo está sobrecargado :

Java Specification Language exige que en este tipo de casos, se elija la sobrecarga más específica :

JLS 15.12.2.5 Elección del método más específico

Si más de un método miembro es accesible y aplicable a una invocación de método, es necesario elegir uno para proporcionar el descriptor para el envío del método en tiempo de ejecución. El lenguaje de programación Java usa la regla de que se elige el método más específico .

A char[] es-an Object , pero no todo Object es-a char[] . Por lo tanto, char[]es más específico que Object, y según lo especificado por el lenguaje Java, la String.valueOf(char[])sobrecarga se elige en este caso.

String.valueOf(char[])espera que la matriz no sea null, y dado que nullse da en este caso, entonces arroja NullPointerException.

La "solución" fácil es emitir nullexplícitamente Objectlo siguiente:

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

Preguntas relacionadas


Moraleja de la historia

Hay varios importantes:

  • Efectivo Java 2nd Edition, Artículo 41: Use la sobrecarga juiciosamente
    • El hecho de que pueda sobrecargarse no significa que deba hacerlo siempre
    • Pueden causar confusión (especialmente si los métodos hacen cosas muy diferentes)
  • Usando un buen IDE, puede verificar qué sobrecarga se selecciona en tiempo de compilación
    • Con Eclipse, puede pasar el mouse sobre la expresión anterior y ver que , de hecho , ¡la valueOf(char[])sobrecarga está seleccionada!
  • A veces quieres emitir explícitamente null(ejemplos a seguir)

Ver también


En casting null

Hay al menos dos situaciones en las nullque es necesario emitir explícitamente a un tipo de referencia específico:

  • Para seleccionar la sobrecarga (como se muestra en el ejemplo anterior)
  • Para dar nullcomo argumento único a un parámetro vararg

Un ejemplo simple de esto último es el siguiente:

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

Entonces, podemos tener lo siguiente:

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

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

Ver también

Preguntas relacionadas

poligenelubricantes
fuente
55
Otra sugerencia: cuando sobrecarga un método y se puede invocar un argumento en dos sobrecargas (como nullen este caso), ¡asegúrese de que ambas sobrecargas actúen de la misma manera con respecto a ese valor!
Joachim Sauer
3
@Joachim: ¡Acabo de leer el artículo y me sorprendió gratamente descubrir que estos dos métodos se discutieron explícitamente! Bloch fue un paso más allá y afirmó que desde entonces String.valueOf(Object)y valueOf(char[])hace cosas completamente diferentes de todos modos (independientemente de nullo no) que tal vez no deberían haber sido sobrecargas en primer lugar.
polygenelubricants
Tengo una pregunta ... si tiene un método que devuelve un objeto, entonces la declaración return null;sería exactamente la misma que return (Object) null;?
user972276
17

El problema es que estás llamando String.valueOf(char[])y no String.valueOf(Object) .

La razón de esto es que Java siempre elegirá la versión más específica de un método sobrecargado que funcione con los parámetros proporcionados. nulles un valor válido para un Objectparámetro, pero también es un valor válido para un char[]parámetro.

Para hacer que Java use la Objectversión, pase a nulltravés de una variable o especifique una conversión explícita a Object:

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

Un error, con el número 4867608, se archivó de esta manera en 2003, que se resolvió como "no solucionará" con esta explicación.

No podemos cambiar esto debido a restricciones de compatibilidad. Tenga en cuenta que es el método de valor de Cadena estática pública (char data []) el que termina siendo invocado y no menciona el reemplazo de "nulo" por argumentos nulos.

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

cbare
fuente
0

Uso String.valueOf(null: Any)en Scala.

Profiterole
fuente