Optimización al concatenar Strings en Java

Posted on Marzo 13, 2008. Filed under: Java | Tags: , , , , , , , |

Al momento de concatenar cadenas, Java ofrece varios métodos de realizar el proceso, pero el rendimiento obtenido entre cada una de estas formas puede ser totalmente diferente.

Veremos cuales son las formas más optimas de realizar esto según cada circunstancia.

Existen 3 maneras de realizar este proceso:

  1. Concatenando mediante el operador +
  2. Concatenando mediante la funcion concat() de la clase String
  3. Utilizando la clase StringBuffer

Para realizar la comparación de rendimientos de cada método utilizaremos un algoritmo simple donde se utiliza cada una de las técnicas, y para el análisis nos valdremos del análisis del Profiler de NetBeans.


package testcadena;
public class Main {
     private static final int cantidadPrueba = 10000;

     public static void main(String[] args) {
         concatenacionBString();
         concatenacionConcat();
         concatenacionSuma();
     }

     private static void concatenacionSuma() {
         String resultado = "inicio";
         for (int i = 0; i < cantidadPrueba; i++) {
             resultado += " hola";
         }
     }

     private static void concatenacionConcat() {
         String resultado = "inicio";
         for (int i = 0; i < cantidadPrueba; i++) {
             resultado.concat(" hola");
         }
     }

     private static void concatenacionBString() {
         StringBuffer resultado = new StringBuffer("inicio");
         for (int i = 0; i < cantidadPrueba; i++) {
             resultado.append(" hola");
         }
     }
}

Mediante la constante cantidadPrueba iremos variando la cantidad de concatenaciones que se realizaran.

Concatenando 1000 cadenas

Realizando la prueba con cantidadPrueba=1000 vemos que el Profiler nos indica:prof1000.gif

Podemos apreciar que el método que utiliza StringBuffer es el más rápido, seguido por el que utiliza concat y por último (más de 100 veces más lento que los anteriores) el método utilizando el operador “+”.

Concatenando 100 cadenas

Bajamos la cantidad de concatenaciones hechas para verificar que pasa:

prof100.gif

Ahora el más rápido es concat seguido de cerca por StringBuffer, pero el operador de concatenación sigue siendo el más lento (aunque ahora la diferencia ya no es tan grande como en la prueba anterior)

Concatenando 10 cadenas

Seguimos bajando la cantidad de concatenaciones:

prof10.gif

Ahora se mantiene y acentúa la tendencia de la anterior prueba, siendo concat el más rápido.

Concatenando 1 cadena

Realizamos la prueba menor, concatenandole a la cadena inicial solo una cadena.

prof1.gif

Como era de esperar sigue siendo más rápido la solución con concat, pero ahora es más rápido la suma antes que el uso de StringBuffer (esto es debido al costo propio de crear el Buffer para la cantidad de concatenaciones realizadas)

Conclusión

De este pequeño análisis podemos obtener las siguientes conclusiones:

  • Nunca es optimo realizar una concatenación de clases mediante el operador de concatenación (+)
  • Para un pequeño número de concatenaciones es mejor utilizar el método concat() de la clase String
  • Para gran cantidad de concatenaciones sobre una cadena, lo mejor es utilizar un StringBuffer

StringBuilder vs. StringBuffer

Agregado el 18 de Marzo de 2008:

Un cuarto método de concatenar String es usando la clase StringBuilder.

StringBuilder tiene una funcionalidad similar a la de StringBuffer, pero la principal diferencia radica en que StringBuilder no está preparada para acceso concurrente tal como lo hace StringBuffer.

Esto puede parecer una desventaja, si usamos múltiples hilos insertando sobre la misma secuencia de caracteres deberemos utilizar obligadamente StringBuffer. Sin embargo encontraremos que en la mayoría de los casos solo un hilo accede a la secuencia de caracteres, siendo todos los mecanismos de sincronización utilizados por StringBuffer completamente inútiles, siendo en estos casos StringBuilder la solución ideal.

Como vimos en los ejemplos anteriores, el StringBuffer es utilizado y consumido por un mismo hilo (el hilo que ejecuta el método), por lo cual esta es una situación ideal para reemplazar StringBuffer por StringBuilder

Creamos un nuevo método:


...
    private static void concatenacionBBuilder() {
        StringBuilder resultado = new StringBuilder("inicio");
        for (int i = 0; i < cantidadPrueba; i++) {
            resultado.append(" hola");
        }
    }
...

y comparamos este método con el que utilizaba StringBuffer, obteniendo:
prof1000b.gif
pudiendo de esta forma comprobar que se ha obtenido una pequeña optimizacion, que era nuestro objetivo.

Ganando más performance

Agregado el 07 de Mayo de 2008:

Si sabemos (o sospechamos por lo menos) cuanto crecerá nuestro StringBuilder ó StringBuffer podemos indicarselo al construirlos.

El problema es que cada vez que hacemos un append() debe crecer antes de copiar la cadena.

Creamos un método nuevo para probar esto:


...
    private static void concatenacionBBuilder2() {
        StringBuilder resultado = new StringBuilder(6*cantidadPrueba);

        resultado.append("inicio");
        for (int i = 0; i < cantidadPrueba; i++) {
            resultado.append(" hola");
        }
    }
...

y estos son los resultados:

Concatenando con StringBuilder

Por lo que si tenemos alguna forma de predecir cuanto crecerá, esto es importante tenerlo en cuenta.

Más Info

Make a Comment

Make A Comment: ( 5 so far )

blockquote and a tags work here.

5 Responses to “Optimización al concatenar Strings en Java”

RSS Feed for Le Funes Comments RSS Feed

A partir de Java 5.0 está la clase StringBuilder que es igual a StringBuffer, pero no es sincronzada. Además tanto StringBuilder como StringBuffer tienen la posibilidad de especificar un tamaño inicial en el constructor. De esa manera no tienen que crecer a cada rato si ya sabes más o menos cuantos caracteres va terminar teniendo.

ignorante
Marzo 14, 2008

Muchas gracias por el aporte Federico.

Es totalmente conveniente utilizar StringBuilder en ambientes donde solo tenemos un hilo accediendo al mismo en comparación de StringBuffer a causa de la sincronización.

Voy a agregar una sección para abarcar este tema.

Saludos

lefunes
Marzo 14, 2008

Ahí agregue la comparativa de StringBuffer y StringBuilder.

Lo mantuve dentro de este mismo post para mantener el espíritu de “encontrar todo en un único lugar”

Saludos y gracias de nuevo Federico

lefunes
Marzo 18, 2008

Ahora dale un tamaño inicial al StringBuffer o StringBuilder y va a andar aún más rápido. El tamaño inicial podría ser de cantidadPrueba * 6 que es exactamente el tamaño final del buffer luego de concatenar todo.

ignorante
Abril 1, 2008

Actualizado el post, muchas gracias nuevamente a Federico por el aporte

lefunes
Mayo 7, 2008

Where's The Comment Form?

Liked it here?
Why not try sites on the blogroll...