Blog jubilado de Paco Ros

Fue bonito mientras duró

Concatenando Strings en Java

Posted by Paco Ros en 4 \04\UTC marzo \04\UTC 2007

Es un truco muy conocido y lo recuerdan en esta entrada de javaHispano.

Cuando se usa el operador “+” con dos instancias de String, el compilador, lo que hace es sustituir la operación por la creación de un StringBuffer.

En el ejemplo del artículo aparecen estos dos fragmentos de código:

// Caso ineficiente (pero típico)
long start = System.currentTimeMillis();
String str = "";
for(int i = 0; i < 10000; i++)
str += i;
System.out.println((System.currentTimeMillis() - start) / 1000.0d);

// Caso eficiente
start = System.currentTimeMillis();
StringBuffer strb = new StringBuffer();
for(int i = 0; i < 10000; i++)
strb.append( i );
System.out.println((System.currentTimeMillis() - start) / 1000.0d);

En el primer fragmento de código, el compilador sustituye el contenido del bucle con un código similar al siguiente:

for (int i=0; i<10000; i++){
    StringBuffer sb = new StringBuffer(str);
    sb.append(i);
    String straux = sb.toString();
    str = sb.toString();
}

A cada iteración se debe ubicar en memoria un nuevo objeto y ese objeto tiene un tamaño cada vez mayor.
La creación dinámica de memoria es una de las operaciones más costosas en Java (y en la mayoría de lenguajes que conozco) y la creación de 10000 instancias de StringBuffer hace que el mismo código resulte mucho más lento.

Ejecutando el código comparativo en mi portátil obtengo 3.277s para ejecutar el bucle con la versión ineficiente y 0.004s en la versión eficiente.

Podéis comprobarlo personalmente copiando y pegando este codigo:

public class Test{
        public static void main(String[] args){
                long start;
                String str;
                StringBuffer strb;

                // Usando el operador "+"
                str = "";
                start = System.currentTimeMillis();
                for(int i = 0; i < 10000; i++) str += i;
                System.out.println((System.currentTimeMillis() - start) / 1000.0d);

                // Usando una instancia de StringBuffer y el método append()
                strb = new StringBuffer();
                start = System.currentTimeMillis();
                for(int i = 0; i < 10000; i++) strb.append(i);
                System.out.println((System.currentTimeMillis() - start) / 1000.0d);

                // Reroducción de lo que hace el compilador en el caso 1
                str = "";
                start = System.currentTimeMillis();
                for (int i=0; i<10000; i++){
                        StringBuffer sbaux = new StringBuffer();
                        sbaux.append(str);
                        sbaux.append(i);
                        String straux = sbaux.toString();
                        str = straux;
                }
                System.out.println((System.currentTimeMillis() - start) / 1000.0d);
        }
}

4 comentarios to “Concatenando Strings en Java”

  1. guillem said

    public class Ineficient
    {
    	public static void main (String[] args)
    	{
    		String str = "";
    		for (int i = 0; i < 20000; i++) str += i;
    	}
    }
    

    Promig de tres execucions: 41.342s.

    public class Eficient
    {
    	public static void main (String[] args)
    	{
    		StringBuffer strb = new StringBuffer ();
    		for (int i = 0; i < 20000; i++) strb.append (i);
    	}
    }
    

    Promig de tres execucions: 0.173s.

    #!/usr/bin/env ruby
    str = ""
    20000.times { |i| str += "#{i}" }
    

    Promig de tres execucions: 2.104s.

    #!/usr/bin/env ruby
    str = ""
    20000.times { |i| str.concat("#{i}") }
    

    Promig de tres execucions: 0.054s.

    (Comentari editat per tal de veure bé el codi ;-))

  2. guillem said

    Otia quin xurro… bé, ho deixaré a http://bulma.net/beowulf/misc/strings.txt

  3. Tribe said

    Vaya, qué sorpresa. Del orden de 250 veces más rápido en Java y 40 veces en Ruby según los resultados de Guillem, bestial.

    Por otra parte impresionante el resaltado de sintaxis en Kate de KDE 3.5.6 al abrir el fichero de texto de Guillem.

    Ah, muy interesantes estas entradas Paco sobre Java, a ver si te animas a poner más ahora que es(?) GPL, como decías en otra entrada :)

    Salud!

  4. Enrique said

    Que bueno justo buscaba como concatenar un int a un string en ruby muchas gracias.

Responder

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

 
A %d blogueros les gusta esto: