Optimización al concatenar Strings en Java

13Mar08

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"); } } }[/sourcecode] 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"); } } ...[/sourcecode] 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"); } } ...[/sourcecode] 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



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

  1. Reblogueó esto en El weBlog de David Rengifoy comentado:
    Valioso material que me sirvió para sustentar el porque de la necesidad de realizar algunas refactorizaciones.

  2. 2 gorka

    La parte de concat() no se está realizando correctamente ya que no se recoge el String devuelto. Para que la comparativa sea en igualdad de condiciones deberías poner:

    resultado=resultado.concat(» hola»);

    Y el rendimiento debería caer hasta el de usar «+» …

    • 3 Geme

      Exacto el concat no está bien implementado. Deberias actualizar el post para ver como afecta al rendimiento

  3. 4 carlos calla

    Se puede crear esas estadisticas de rendimiento en Eclipse?, gracias

    • 5 juan fernando arango

      Tengo la misma duda, pero quisiera saber como hacer estas estadisitcas en netbeans. Sería de gran ayuda. Quien sabrá?…

  4. Buen dato, excelente blog, mis felicitaciones. Un saludo

  5. 7 Trini

    A pesar del tiempo que hace que publicaste esta entrada, por si sirve de algo, enhorabuena: has resuelto completamente mis dudas. Sabía que la concatenación con el operador suma no era eficaz pero no sabía a partir de qué punto se notaba realmente la diferencia. Con el análisis que has hecho con distinto número de concatenaciones ha quedado todo muy claro.

  6. que buena… muy buen aporte :D, ¿como hiciste para generar esas estadisticas con netbeans? se te agradeceria un monton, saludos.

    • 9 juan fernando arango

      Yo también tengo la misma duda. como hacer estas estadísticas… sería interezante conocer el rendimiento de mi programa de esa manera… algún plugin o algo?.

  7. 10 Cristian

    Excelente aporte estimado, muy concreto y preciso, es muy útil y claramente le servirá a mucha gente incluyéndome.

    Gracias!

  8. 11 angi494

    hola, alguien sabria como realizar un macro en java.. por ejemplo: var=’campo.getText()’ donde la variable campo va cambiando y de acuerdo al nombre que toma, mostrara los datos de la sentencia…. Gracias….

  9. 12 Michael

    Muy buen aporte, te felicito por buscar la eficiencia y no solo la eficacia.

    saludos, éxitos siempre

  10. 13 drevel

    Hay que ser estupido para usar un StringBuffer de la manera en que vemos usarse aqui…. esto es una tomadura de pelo.

    • ¿Nadie usa StringBuffer así en vez de utilizar StringBuilder? ¿No pasan cosas similares con Vector y ArrayList?

      Estimado drevel quizás tu nivel profesional sea muy avanzado como para perder el tiempo proponiendo algo mejor, igual aprecio tu interés, aunque esto no cambia mi idea que haya colegas a los que esta información le servirá como en su momento me sirvió a mi.

      No dejes de enviarme algún link de tus artículos para aprender un poco más.

      Saludos

  11. 15 fernando

    hey gracias, pero estube haciendo pruebas y no siempre se obtiene el mismo resultado…

  12. Fernando, es el profiler. Viene con netbeans 6.0 en adelante.

  13. 17 fernando

    Oye muchas gracias, algo que me dejo inquieto y lo busque pero encontre forma, es la de como obtienes esa barra «call tree method» en netbeans. Espero y me puedas decir muchas gracias

  14. 18 Rene Gonzalez

    Excelente articulo. Actualmente uso a la ligera la concatenacion de string. Ahora tendre mucho mas cuidado. Gracias y felicitaciones.

  15. 19 lefunes

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

  16. 20 ignorante

    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.

  17. 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

  18. 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

  19. 23 ignorante

    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.