String o StringBuffer?

Muchas veces al programar considero muchas cuestiones, como lo es la rapidez, la eficacia del código, y la estabilidad.

En una de esas veces, al intentar programar la lectura de un archivo de texto con java, utilice la clase String para almacenar los caracteres al estilo cadena+=nuevacadena. El archivo era muy pequeño, por lo que la lectura del mismo se hacia a una velocidad considerable, así que incremente la cantidad de información para ver que tan rápido podía concatenar las cadenas.

Mi sorpresa fue grande, pues a considerar que la primer prueba con el archivo pequeño fue tan rápida que no imagine que al incrementar la información la operación pudiera complicarse y hacerse mas tardía.

Intente hacer otra cosa, sin embargo, opte por otra opción que es utilizar StringBuffer, así que hice pruebas para comparar velocidades entre String y StringBuffer.

Para ello, primero diseñe un programa que midiera el tiempo de ejecución, así que debía medir el tiempo antes de iniciar la operación y una vez terminada medirlo de nuevo en una nueva variable para después restarle el primer tiempo medido.

El código de medición quedará así.

main.java

JAVA:
  1. public class main {
  2.  
  3.     public static void main(String args[]){
  4.         double tini = System.currentTimeMillis();
  5.  
  6.             //operaciones o procesos
  7.  
  8.         double ttotal = System.currentTimeMillis() - tini;
  9.         System.out.println("Tiempo de ejecución: " + ttotal/1000 + " seg");
  10.     }
  11. }

En la linea donde esta el comentario "//operaciones o procesos" vamos a poner el proceso que queremos medir, así que me propuse a hacer otra clase que contuviera dos métodos, uno llamado MString(int n) para la clase String y otro llamado MStringBuffer(int n) para la clase StringBuffer. Ambos reciben un valor para n del tipo entero que contendrá el numero e concatenaciones que queremos hacer.

concatenacion.java

JAVA:
  1. public class concatenacion {
  2.  
  3.     public concatenacion(){
  4.  
  5.     }
  6.  
  7.     public void MString(int n){
  8.         String temp = new String("");
  9.         for(int k=0;k<n;k++)
  10.             temp+="1";
  11.     }
  12.     public void MStringBuffer(int n){
  13.         StringBuffer temp = new StringBuffer();
  14.         for(int k=0;k<n;k++)
  15.             temp.append("1");
  16.     }
  17. }

Ambos métodos MString y MStringBuffer son parecidos, ambos con un for de 0 a n, pero podemos darnos cuenta que la concatenación de String la realizamos de la forma temp+="1" y la de StringBuffer de la forma temp.append("1");

La clase main la modifique de esta manera para que me diera el tiempo para ambos procesos.

main.java

JAVA:
  1. public class main {
  2.  
  3.     public static void main(String args[]){
  4.         double tini;
  5.         double ttotal;
  6.         concatenacion temp;
  7.         int n=100;
  8.  
  9.         tini = System.currentTimeMillis();
  10.  
  11.             temp = new concatenacion();
  12.             temp.MString(n);
  13.  
  14.         ttotal = System.currentTimeMillis() - tini;
  15.         System.out.println("Tiempo de ejecución para String: " + ttotal/1000 + " seg");
  16.  
  17.         tini = System.currentTimeMillis();
  18.  
  19.             temp = new concatenacion();
  20.             temp.MStringBuffer(n);
  21.  
  22.         ttotal = System.currentTimeMillis() - tini;
  23.         System.out.println("Tiempo de ejecución para StringBuffer: " + ttotal/1000 + " seg");
  24.     }
  25. }

Donde n tendrá el numero de concatenaciones que haremos de "1", y en primera instancia le puse el valor de 100 para ver al diferencia.

Pruebas

Al correr main.java con n=100
Tiempo de ejecución para String: 0.0010 seg
Tiempo de ejecución para MString: 0.0 seg

Aquí la diferencia es mínima, nada notable, ahora hagamos una prueba mas.

Al correr main.java con n=10000
Tiempo de ejecución para String: 0.299 seg
Tiempo de ejecución para MString: 0.0020 seg

Aquí ya podemos ver una diferencia mas notable, pero que tal con la siguiente prueba.

Al correr main.java con n=100000
Tiempo de ejecución para String: 42.117 seg
Tiempo de ejecución para StringBuffer: 0.01 seg

Claramente vemos la diferencia de los tiempos.

Conclusión: para este tipo de cuestiones de concatenación de información (cadenas) muy grande, es preferible usar StringBuffer.

by: lesthack

Posts Similares, quizá:

3 Comments

  1. Posted May 23, 2008 at 8:06 pm | Permalink

    Y espera! Si estás intentando modificar un cadena / StringBuffer desde un solo thread (como es bastante probable), usando StringBuilder es MUCHISIMO más rápido, pues no tiene locks de sincronización, y se comporta exactamente igual que un StringBuffer.

    También el comportamiento cuadrático de la concatenación de cadenas con + también es esperado. Cada que concatenas una cadena tienes que tener el espacio en memoria reservado para las dos cadenas originales, y reservar espacio para crear una cadena extra, copiar ambas cadenas originales, y reemplazar una de las cadenas originales. Ouch.

    (Offtopic: Lo siento por no avisar antes que me iba a Redmond chamaco, pero pues estamos en contacto!)

  2. iceman
    Posted May 24, 2008 at 6:06 pm | Permalink

    Que buenas pruebas jorge, buen post!!!, eso de los strings en java es interesante.
    Si tienes razón lhchavez , hace tiempo comparé StringBuilder y StringBuffer y se nota, de hecho StringBuilder es el que se recomienda usar desde que salió (creo que en la versión 1.5).
    Solo una sugerencia jorge, remarca cuando es recomendable usar la clase String, y el por que…y es que aun que al ultimo mencionas: “Conclusión: para este tipo de cuestiones de concatenación de información (cadenas) muy grande, es preferible usar StringBuffer. “, alguien nuevo en java podría pensar que StringBuffer o StringBuilder sustituye a String.

  3. Posted June 28, 2008 at 8:41 pm | Permalink

    Hola a todos.

    Como ya comentaban StringBuilder y StringBuffer son dos cosas diferentes, lo unico que los asemeja es que ambos son “mutables” (La clase String es “inmutable” por eso la necesidad de la existencia de estas).

    Ahora bien StringBuffer esta sincronizado, StringBuilder No, por ende el acceso a StringBuilder es mas rápido que al de StringBuffer.

    Saludos.

Post a Comment

Your email is never shared. Required fields are marked *

*
*