Java: StringBuilder y StringBuffer
Publicado el 7 de septiembre de 2010A 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-
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 […]
-
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 […]
-
Trabajo con Strings (Clases: String, StringBuilder, StringTokenizer, Character) | Técnicas de programación |
5 noviembre. 2014 - 18:54
[…] StringBuilder: https://picandocodigo.net/2010/java-stringbuilder-stringbuffer/ […]
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.
Alejandro Segovia 7 septiembre. 2010 - 11:17
Oops… parece que los operadores de < > armaron lío con el markup. Voy a ver de poner el ejemplo en mi blog más tarde.
Saludos!
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.
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
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…
Mizo 29 septiembre. 2010 - 05:11
Muy buen recordatorio, y ahora que estoy preparando el examen de Java programmer =)
Moritatux 9 octubre. 2010 - 02:22
Pues ha quedado muy claro estimado, gracias.
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?
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:
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!
Juan Valdez 24 abril. 2013 - 12:15
Excelente explicacion.
R 15 marzo. 2014 - 11:01
Muchas gracias por compartir este conocimiento, me ha servido de mucho esta información 🙂
Milton Marino 3 abril. 2014 - 17:58
Gracias…!
Joel Barcenas 29 mayo. 2018 - 18:01
Muy buen post. sigue así!