Concatenación de cadenas nulas en Java


¿Por qué funciona lo siguiente? Yo esperaría que se lanzara un NullPointerException.

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Author: yavoh, 2010-11-23

5 answers

¿Por qué debe funcionar?

El JLS 5, Sección 15.18.1.1 JLS 8 § 15.18.1 "Operador de Concatenación de cadenas +" , que conduce a JLS 8, § 5.1.11 "Conversión de cadenas" , requiere que esta operación tenga éxito sin fallar:

...Ahora solo se deben considerar los valores de referencia. Si la referencia es null, se convierte en la cadena "null" (cuatro caracteres ASCII n, u, l, l). De lo contrario, la conversión es se realiza como si invocara el método toString del objeto referenciado sin argumentos; pero si el resultado de invocar el método toString es null, entonces se usa la cadena "null" en su lugar.

¿Cómo funciona?

¡Echemos un vistazo al bytecode! El compilador toma tu código:

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"

Y lo compila en bytecode como si hubiera escrito esto:

String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"

(Puede hacerlo usted mismo utilizando javap -c)

Los métodos anexar de StringBuilder todos manejan null muy bien. En este caso, debido a que null es el primer argumento, String.valueOf() se invoca en su lugar ya que StringBuilder no tiene un constructor que tome cualquier tipo de referencia arbitraria.

Si hubieras hecho s = "hello" + s en su lugar, el código equivalente sería:

s = new StringBuilder("hello").append(s).toString();

Donde en este caso el método append toma el null y entonces lo delega a String.valueOf().

Nota: Cadena la concatenación es en realidad uno de los raros lugares donde el compilador decide qué optimización(es) realizar. Como tal, el código "equivalente exacto" puede diferir de un compilador a otro. Esta optimización está permitida por JLS, Sección 15.18.1.2:

Para aumentar el rendimiento de la concatenación de cadenas repetidas, un compilador Java puede usar la clase StringBuffer o una técnica similar para reducir el número de objetos de cadena intermedios que se crean por evaluación de una expresión.

El compilador que utilicé para determinar el "código equivalente" anterior fue el compilador de Eclipse, ecj.

 163
Author: Mark Peters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 08:36:49

Ver sección 5.4 y 15.18 de la especificación del lenguaje Java:

La conversión de cadena se aplica solo a operandos del operador binario + cuando uno de los argumentos es una cadena. En este único caso especial, el otro el argumento a + se convierte en un Cadena, y una nueva cadena que es la la concatenación de las dos cadenas es el resultado del +. Conversión de cadenas se especifica en detalle dentro de la descripción de la cadena concatenación operador+.

Y

Si solo una expresión de operando es de tipo cadena, entonces la conversión de cadena es realizado en el otro operando a produce una cadena en tiempo de ejecución. El el resultado es una referencia a una cadena objeto (recién creado, a menos que el expression es una constante en tiempo de compilación expresión (§15.28)) que es la concatenación de los dos operando cadena. Los personajes de la el operando izquierdo precede al personajes de la mano derecha operando en la cadena recién creada. Si un operando de tipo String es null, entonces la cadena "null" se utiliza en lugar de ese operando.

 23
Author: Jonathon Faust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 20:53:03

La segunda línea se transforma en el siguiente código:

s = (new StringBuilder()).append((String)null).append("hello").toString();

Los métodos append pueden manejar argumentos null.

 11
Author: Roland Illig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 20:49:31

No está usando el "null" y por lo tanto no obtiene la excepción. Si desea el NullPointer, simplemente haga

String s = null;
s = s.toString() + "hello";

Y creo que lo que quieres hacer es:

String s = "";
s = s + "hello";
 10
Author: krico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 20:50:35

Este es el comportamiento especificado en la API de Java String.valueOf(Object) método. Cuando haces concatenación, valueOf se usa para obtener la representación String. Hay un caso especial si el Objeto es null, en cuyo caso se utiliza la cadena "null".

public static String valueOf(Object obj)

Devuelve la representación de cadena del argumento Objeto.

Parámetros: obj - un Objeto.

Devuelve:

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

 7
Author: wkl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 20:50:27