Sin excepción al escribir con un valor nulo en Java


227
String x = (String) null;

¿Por qué no hay excepción en esta declaración?

String x = null;
System.out.println(x);

Se imprime null. Pero el .toString()método debería arrojar una excepción de puntero nulo.


¿De qué excepción estás hablando, compilador?
Sajan Chandran

Respuestas:


323

Puede emitir nulla cualquier tipo de referencia sin obtener ninguna excepción.

El printlnmétodo no arroja un puntero nulo porque primero verifica si el objeto es nulo o no. Si es nulo, simplemente imprime la cadena "null". De lo contrario, llamará al toStringmétodo de ese objeto.

Agregar más detalles: métodos de impresión internamente llaman String.valueOf(object)método en el objeto de entrada. Y en el valueOfmétodo, esta comprobación ayuda a evitar una excepción de puntero nulo:

return (obj == null) ? "null" : obj.toString();

Para el resto de su confusión, llamar a cualquier método en un objeto nulo debería arrojar una excepción de puntero nulo, si no un caso especial.


1
@JunedAhsan ¿qué casos especiales causarían que no arroje un NPE?
Holloway

@Trengot Marque uno mencionado en la respuesta de Peter a continuación.
Juned Ahsan

144

Puede emitir nulla cualquier tipo de referencia. También puede llamar a métodos que manejan a nullcomo argumento, por ejemplo, System.out.println(Object)sí, pero no puede hacer referencia a un nullvalor y llamar a un método sobre él.

Por cierto, hay una situación difícil en la que parece que puede llamar a métodos estáticos en los nullvalores.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.

12
Guau. Si me preguntaran, estaría 100% seguro de que arrojaría una excepción. Un caso complicado de hecho.
Magnilex

2
@Magnilex: ¡Absolutamente! Esta es una típica pregunta capciosa del examen OCPJP.
ccpizza

3
¿No es esto porque el compilador en bytecode lo "optimiza" de t.yield() -> Thread.yeld() todos modos? Similar a cómo final int i = 1; while (i == 1)está optimizado parawhile(true)
SGal

@SGal Es aún mejor porque la segunda optimización es AFAIK no obligatoria mientras que la primera sí lo es.
Paul Stelian

36

Esto es por diseño. Puede emitir nulla cualquier tipo de referencia. De lo contrario, no podría asignarlo a variables de referencia.


¡Gracias! ¡Esta nota sobre la asignación de variables nulas a de referencia es realmente útil!
Max

22

La conversión de valores nulos es necesaria para la siguiente construcción donde un método está sobrecargado y si se pasa nulo a estos métodos sobrecargados, entonces el compilador no sabe cómo aclarar la ambigüedad, por lo tanto, necesitamos escribir nulo en estos casos:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

De lo contrario, no podría llamar al método que necesita.


En la mayoría de los casos, la conversión es implícita, por ejemplo, String bar = null;convierte el nullvalor en String. Hasta ahora, solo tuve que emitir nulo explícitamente en una prueba en la que un método estaba sobrecargado y quería probar su comportamiento con una entrada nula. Aún así, es bueno saber que estaba a punto de escribir una respuesta similar antes de encontrar la suya.
Vlasec

Dato curioso: l instanceof Longy s instanceof Stringvolveremos falseen estos casos.
Attila Tanyi

7

Println(Object) usos String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) hace cheque nulo.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}


3

Como otros han escrito, puede lanzar nulo a todo. Normalmente, no necesitarías eso, puedes escribir:

String nullString = null;

sin poner el elenco allí.

Pero hay ocasiones en que tales elencos tienen sentido:

a) si desea asegurarse de que se llame a un método específico, como:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

entonces haría una diferencia si escribes

foo((String) null) vs. foo(null)

b) si tiene la intención de usar su IDE para generar código; por ejemplo, normalmente escribo pruebas unitarias como:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Estoy haciendo TDD; Esto significa que la clase "MyClassUnderTest" probablemente todavía no existe. Al escribir ese código, puedo usar mi IDE para generar primero la nueva clase; y luego generar un constructor que acepte un argumento "Lo que sea" "listo para usar": el IDE puede deducir de mi prueba que el constructor debe tomar exactamente un argumento de tipo Whatever.


2

Imprimir :

Imprime un objeto. La cadena producida por el método String.valueOf (Object) se traduce a bytes

Valor de :

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

Simplemente devolverá una cadena con el valor "nulo" cuando el objeto lo sea null.


2

Esto es muy útil cuando se usa un método que de otra manera sería ambiguo. Por ejemplo: JDialog tiene constructores con las siguientes firmas:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

Necesito usar este constructor, porque quiero configurar GraphicsConfiguration, pero no tengo padre para este diálogo, por lo que el primer argumento debería ser nulo. Utilizando

JDialog(null, String, boolean, Graphicsconfiguration) 

es ambiguo, por lo que en este caso puedo reducir la llamada al convertir nulo en uno de los tipos admitidos:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)

0

Esta característica del lenguaje es conveniente en esta situación.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Si memberHashMap.get ("Nombre") devuelve nulo, aún querría que el método anterior devuelva nulo sin lanzar una excepción. No importa cuál sea la clase, nulo es nulo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.