Concatenación de cadenas en Java: Optimizaciones realizadas por el compilador

08may08

La máquina virtual de Java no conoce al operador de concatenación (+) a la hora de ejecutar nuestro código.
Por este motivo el compilador se encarga de traducir los lugares donde este operador aparece por el código necesario que permite cumplir con el mismo propósito y de forma óptima.

Veremos cuales son las traducciones realizadas por el compilador y como podemos aprovecharlas a nuestro favor.

Definiciones

Antes de empezar vamos a definir algunos términos, que aunque no sean definidos de una forma muy formal, permitirán una mejor comprensión del texto:

  • Cadena: Una instancia de la clase String. El objeto puede estar asignado a una variable, una constante o no (cadenas anónimas)
  • Cadenas Anónimas: Cadenas no asociadas a ningún objeto que se crean y utilizan en la sentencia que se declaran, y luego son descartadas. Por ejemplo en:
System.out.println("Hola Mundo");

la cadena “Hola Mundo” se crea y utiliza en el System.out.println y luego se descarta.

Caso 1: Concatenación de cadenas anónimas

Aunque muchas veces parezca incorrecta o ineficiente la realización de concatenación de dos cadenas anónimas en vez de solo utilizar una, resulta ser lo mismo luego de pasar por el compilador, ya que si tenemos por ejemplo:

//...
String a = "Hola " + "Mundo";
//...

Se convertirá en:

//...
String a = "Hola Mundo";
//...

Viendo la maquina virtual lo mismo que si hubiéramos asignado “Hola Mundo” de primera intención.

Cuál puede ser el beneficio entonces de separar una cadena anónima en dos o más pedazos?

El beneficio que encontramos no es al momento de correr nuestro programa, sino al momento de mantenerlo, ya que en varias ocasiones permitirá una mejor lectura del mismo:

String fragmento = "Por lo tanto, los que no son totalmente conscientes de"
+ " la desventaja de servirse de las armas no pueden ser totalmente conscientes"
+ " de las ventajas de utilizarlas";

Caso 2: Concatenación de constantes

Si tenemos definidas constantes y las concatenamos con alguna cadena anónima o entre si, primero que nada el compilador realizará el intercambio de las constantes por la cadena que representan y luego las trata como el caso anterior. Por ejemplo:

//...
public static final String CONSTANTE_A = "AAA";
private static final String CONSTANTE_B = "BBB";
public final String CONSTANTE_C = "CCC";
private final String CONSTANTE_D = "DDD";
//...
String a = "Mostrar " + CONSTANTE_A;
String b = "Mostrar " + CONSTANTE_B;
String c = "Mostrar " + CONSTANTE_C;
String d = "Mostrar " + CONSTANTE_D;
//...

Después de compilar tendremos:

//...
String a = "Mostrar AAA";
String b = "Mostrar BBB";
String c = "Mostrar CCC";
String d = "Mostrar DDD";
//...

Por lo que podemos ver que no importa el modificador de acceso o si es estática o no, mientras el valor de la constante este disponible a la hora de compilar, será reemplazado en la concatenación.

En este caso podemos ver que la ventaja que trae aparejado el uso de constantes, que es permitirnos hacer mas legible nuestro código no va en contraposición a la de la tener una buena eficiencia en la ejecución, ya que no se perderá tiempo realizando concatenaciones porque fueron realizadas al momento de la compilación.

Caso 3: Concatenación de variables finales

Al igual que en el caso anterior si tenemos definida un variable declarada dentro de un método como final y esta la concatenamos, el compilador la reemplazara la referencia por el valor que representa la variable final.

Por ejemplo:

//...
final String a = " AAA";
String b = "Mostrar " + a;
//...

Después de compilar obtendremos:

//...
final String a = " AAA";
String b = "Mostrar AAA";
//...

Otra vez tenemos las mismas ventajas del punto anterior.

Caso 4: Concatenación de variables

La concatenación de variables es distinta de los casos anteriores debido a que en ningún caso el compilador puede suponer el valor almacenado en las mismas. Como no sabe con que valores se contará, lo que se realiza a la hora de compilar es armar un StringBuilder e irle agregando las cadenas que queremos visualizar.

Esta vez la sentencia quedará preparada y la concatenación real se realizara durante el momento de ejecución.

Por ejemplo:

//...
String v = "Mundo";
//...
String resultado = "Hola " + v;
//...

Como se puede observar, no se puede asegurar de ninguna manera que el valor de “v” va a seguir siendo “Mundo” al momento de concatenar, por lo que el compilador genera:

//...
String resultado = (new StringBuilder()).append("Hola ").append(v).toString();
//...

Básicamente al ejecutarse realizará lo siguiente:

- creará una instancia de StringBuilder
– le agregará la cadena “Hola “
– le agregará el valor de la variable “v”
– obtendrá la cadena resultante
– asignará la cadena resultante a la variable “resultado”

Nuevamente lo que ganamos es expresión a la hora de analizar nuestro código. Veamos un ejemplo ilustrativo de esto, es más difícil entender a simple vista esto:

//...
String res = "Cantidad de tomates: ".concat(Integer.toString(cantidad));
//...

A esto:

//...
String res = "Cantidad de tomates: " + cantidad;
//...

Caso 5: Caso especial de concatenación de variables

Existe un caso especial a la hora de realizar optimizaciones que el compilador no es capaz de darse cuenta, cuando a una variable debemos concatenarle cadenas en varias sentencias, por ejemplo un caso muy simple:

//...
String e = "Hola";
for (int i = 0; i < 100; i++) {
     e += " mundo";
}
//...

En este caso el código generado será el siguiente:

//...
String e = "Hola";
for (int i = 0; i < 100; i++){
     e = (new StringBuilder()).append(e).append(" mundo").toString();
}
//...

Por lo tanto cada nueva iteración del bucle lleva aparejado la creación de un StringBuilder para agregarles las cadenas y asignárselo a la variable “e”

Lo que se puede realizar es crear un StringBuilder e irlo asignando en cada iteración, de la forma:

//...
StringBuilder sb = new StringBuilder("Hola");
for (int i = 0; i < 100; i++) {
     sb.append(" mundo");
}
String e = sb.toString();
//...

Entonces la ejecución se resume a:

- creará una instancia de StringBuilder con el texto inicial (“Hola”)
– le agregará la cadena “ mundo“ una vez por cada bucle
– obtendrá la cadena resultante
– asignará la cadena resultante a la variable “e”

Como pudimos ver en un post anterior la principal ventaja es la gran cantidad de tiempo ganado durante la ejecución.

Conclusión

Como pudimos ver a lo largo de estos casos es que es importante saber como el compilador hace las cosas para de esa forma poder preocuparnos más en el diseño/mantenimiento de nuestras aplicaciones a estar optimizando código que optimizara el compilador y que visualmente es difícil de comprender.

Si es eficiente y bello, no se puede pedir más.

Nota Final

Todo el análisis realizado sobre el funcionamiento del compilador a partir del código generado por el mismo, fue realizado utilizando Jad para descompilar los .class

En el post anterior hablamos como integrar Jad a NetBeans mediante NBJAD.

Es muy bueno el ejercicio de generar clases y analizar que optimizaciones realizo el compilador, ayudándonos esto a tener una base más amplia donde apoyarnos a la hora de desarrollar.

Espero les sirva.
Saludos.

Más Info

About these ads


5 Responses to “Concatenación de cadenas en Java: Optimizaciones realizadas por el compilador”

  1. Está muy buena la nota. Aunque no sea nuevo para mi, reconozco que está muy bien explicado y derriba algunos mitos que cuestan desactivar.

    Muy interesante lo de JAD. No lo conocía en particular, especialmente por la posibilidad de poder integrarlo al IDE. Me lo apunto para probarlo.

  2. jajAJAJAJAJAJA


  1. 1 Optimización al concatenar Strings en Java « Le Funes
  2. 2 Inclusión condicional de bloques de código en Java mediante constantes « Le Funes
  3. 3 Going to wp1018907.server-he.de

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s


Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

%d personas les gusta esto: