Java: StringBuilder y StringBuffer

Publicado el 7 de septiembre de 2010
Java

Java

A continuación un pequeño conocimiento de la plataforma Java que me gustaría compartir por acá. Recientemente tuve que explicar la diferencia entre usar un StringBuilder y un StringBuffer. Recuerdo perfectamente haber aprendido la diferencia académicamente. Pero al momento de responder, me quedé en blanco.

Para empezar, hay que conocer un poco la clase String. Un objeto String tiene la cualidad de ser un objeto inmutable. Esto quiere decir que una vez que es instanciado, no puede cambiar su estado. Por ejemplo en el siguiente código:

String miString = "   Picando Código   ";
miString.trim(); //método para acortar los espacios
System.out.println(miString);

La segunda línea llama a un método de la clase que devuelve una copia del objeto sin espacios en los extremos del String. Pero al hacer un println, vamos a ver en la salida estándar:

"   Picando Código   "

ya que el String no ha cambiado. Si quisiéramos que el String “cambie”, haríamos algo así:

String miString = "   Picando Código   ";
miString = miString.trim();
System.out.println(miString);

Pero lo que estamos haciendo ahora, es usar una copia del objeto y modificándolo. El println mostrará

"Picando Código"

Pero habremos usado dos objetos para lograr esto. Lo mismo pasa a la hora de concatenar Strings con el operador “+”. Podemos hacer lo siguiente:

String blog = "Picando";
blog += " ";
blog += "Código";
System.out.println(blog);

El resultado final del String será el mismo: “Picando Código”. Pero al ser String un objeto inmutable, con cada concatenación, estamos creando un objeto nuevo. Si bien en pocos objetos no es importante, a la hora de trabajar con muchos String, sería un despilfarro de memoria. Por ejemplo si recorriéramos una colección y quisiéramos agregar algo a un String por cada elemento, tendríamos el heap lleno de objetos String que no nos importan más…

Esto sería la teoría, aunque aparentemente a partir de la versión 1.4 de la JDK, el código:

String miString =  "Picando" + " " + "Código";

Se compilaría a:

miString = new StringBuilder().append("Picando").append(" ").append("Código").toString();

De todas formas, Java provee soporte especial para la concatenación de Strings con las clases StringBuilder y StringBuffer. Un objeto StringBuilder es una secuencia de caracteres mutable, su contenido y capacidad puede cambiar en cualquier momento. Además, a diferencia de los Strings, los builders cuentan con una capacidad (capacity), la cantidad de espacios de caracteres asignados. Ésta es siempre mayor o igual que la longitud (length) y se expande automáticamente para acomodarse a más caracteres.

Un String puede convertirse en StringBuilder instanciando un StringBuilder y pasando el String como parámetro. A su vez, un StringBuilder puede convertirse en un String con el método toString().

Los operadores principales de la clase StringBuilder son append e insert. Éstos se implementaron sobrecargados para aceptar cualquier tipo de datos. Cada uno convierte un dato en String y concatena o inserta los caracteres de dicho String al StrinBuilder. El método append agrega los caracteres al final de builder mientras que insert los agrega en un punto específico. En general entonces es equivalente escribir:

StringBuilder sb = new StringBuilder;
sb.append(x); //equivale a:
sb.insert(sb.length(), x);

He leído varios fundamentos a favor y en contra de concatenar Strings y usar StringBuilder, discutiendo que no hay diferencias. En este momento no encuentro una fuente técnica que ponga fin a esa discusión. Personalmente al ser String un objeto inmutable, me suena a más coherente usar un StringBuilder para esta función, pero con las optimizaciones de la JDK actualmente, parece que en rendimiento sería lo mismo concatenar Strings que usar un StringBuilder.

Bien, hasta acá hice un repaso de las clases String y StringBuilder. Pero no respondí a la pregunta:

¿Cuál es la diferencia entre un StringBuilder y un StringBuffer?

La diferencia entre un StringBuilder y un StringBuffer es que un StringBuffer provee métodos sincronizados por lo que es seguro usarlos en un ambiente multi-hilos. Los métodos son sincronizados donde sea necesario, para que las operaciones en cualquier instancia de un StringBuffer puedan comportarse como si ocurrieran en serie de manera consistente con el orden de las llamadas a los métodos hechas por cada hilo.

Generalmente es más común el uso de StringBuilder. Usar StringBuffer en un ambiente de un solo hilo de ejecución no tiene sentido, y al tener métodos sincronizados, es más lenta en general.

Así que ahí tienen algo que nunca me voy a olvidar, la diferencia entre StringBuilder y StringBuffer 😛
Lo bueno de posts como éste son reafirmar conocimientos, y que generalmente se genera un poco más de conocimiento con el intercambio con los comentarios (bienvenidos sean comentarios, correcciones y demás aportes sobre el tema).

16 comentarios en este post

Feed de comentarios
  1. Avatar

    Alejandro Segovia 7 septiembre. 2010 - 11:16

    Hola Fernando,

    StringBuilder definitivamente me recuerda a los stringstreams de C++, una forma similar de armar strings concatenando variables de cualquier tipo.

    stringstream ss;
    ss << "pi = " <> s1 >> s2 >> num;

    Realmente facilitan la escritura de Parsers 😉

    Un saludo.

    Google Chrome 5.0.342.9 GNU/Linux 64 bits
    • Avatar

      Fernando 8 septiembre. 2010 - 21:23

      ¡A esta altura ya tendrías que haber aprendido a escribir código en los comentarios! 😛

      ¡Gracias por el post en Algorithmia! Ese tipo de intercambios hacen interesante esto de tener blog… C++ es una materia pendiente para mí. Actualmente estoy buscando más conocimiento en Java, pero me encantaría poder usar C++ en un proyecto real para aprender algún día.

      GNU IceCat 3.6.8 GNU/Linux 64 bits
  2. Avatar

    Francisco 7 septiembre. 2010 - 12:40

    Tenia entendido que el compilador de java optimiza los strings. Osea que si tu defines

    miString = “Hola” + ” como ” + “estas”

    el lo optimiza a:

    miString = new StringBuilder().append(“Hola”).append(” Como “).append(“estas”).toString();

    Pero siempre es bueno entender y utilizar las mejoras practicas y no dejarle toda la chamba al compilador.

    Saludos

    Firefox 3.6.8 Windows XP
  3. Avatar

    Alex 9 septiembre. 2010 - 10:24

    Muy buen post, creo que tampoco lo olvidare, y mientras java no haga sus cambios internos, tomare la mejor decision al momento de implementar strings 🙂

    otro post mas, juye…

    GNU IceCat 3.6.3 GNU/Linux 64 bits
  4. Avatar

    Daniel 17 enero. 2012 - 03:26

    Yo tengo una duda: se puede crear un StringBuilder apartir de un StringBuffer y viceversa, es decir pasando uno de estos al constructor… es que revise la API pero no viene un constructor:

    StringBuilder(StringBuffer buffer) ni uno
    StringBuffer(StringBuilder build)

    sin embargo lo intente y no marco errores, entonces.
    ¿se puede o no?

    Firefox 3.6.23 Ubuntu
    • Avatar

      Fernando 17 enero. 2012 - 10:38

      Recuerda que ambas clases son exactamente iguales, la única diferencia es que el StringBuffer contiene métodos sincronizados.

      El código que escribiste funciona por el siguiente constructor:

      StringBuilder(CharSequence seq)
      StringBuffer(String str)

      Si te fijas la documentación de las clases, vas a ver que ambas implementan la interfaz CharSequence. Por esto se puede construir cualquiera de los dos a partir de un objeto de la clase StringBuilder o StringBuffer.

      ¿En qué caso necesitas hacer algo así?

      ¡Saludos!

      Firefox 9.0.1 GNU/Linux 64 bits
  1. WordPress Varrojo@Linux » C++ StringStreams | 7 septiembre. 2010 - 13:18

    […] Briano, de Picando Código, está con un artículo muy interesante hoy sobre StringBuilders y StringBuffers de Java. El artículo describe el por qué un desarrollador querría hacer uso de éstos en vez de los […]

  2. WordPress Nuevo camino | Picando Código | 19 marzo. 2012 - 09:02

    […] equipo que van pasando uno a la vez.  Las preguntas no fueron tanto técnicas del estilo “¿Cuál es la diferencia entre un StringBuilder y un StringBuffer?” o “Del 1 al 10 cómo te puntuarías en X lenguage?”. Hubieron preguntas de […]

  3. WordPress Trabajo con Strings (Clases: String, StringBuilder, StringTokenizer, Character) | Técnicas de programación | 5 noviembre. 2014 - 18:54

Dejar un comentario

Notificarme los nuevos comentarios por correo electrónico. Tambien puedes suscribirte sin comentar.

Toasty!