¿String o StringBuffer ? .Hay pocas clases con las que trabajemos mas a menudo que la clase String . Sin embargo mucha gente no conoce como funciona esta clase a detalle lo cual puede llevarnos a malentendidos .Vamos a ver un código muy sencillo.
package com.arquitecturajava; public class Principal { public static void main(String[] args) { String cadena = ""; long numero1 = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { cadena += "hola" + "que" + "tal" + "estas"; } long numero2 = System.currentTimeMillis(); System.out.println(numero2 - numero1); } }
String y Bucles
En este bloque de código ejecutamos un sencillo buble for que concatena cadenas y calculamos el tiempo que tarda en hacerlo el procesador. Sorpresivamente el procesador tarda casi un segundo en ejecutar este código tan sencillo. En principio unicamente estamos construyendo objetos.
String Inmutable
Sin embargo los objetos de tipo String tienen una peculiaridad son “Inmutables” esto quiere decir que una vez hemos construido el objeto, este no se puede modificar .En el caso de las cadenas son almacenadas e un pool de Strings para su posterior uso.
Si revisamos el código de dentro del bucle for podremos nos parecerá relativamente sencillo .
for (int i = 0; i < 10000; i++) { cadena += "hola" + "que" + "tal" + "estas"; }
En la linea se construyen 4 objetos y se concatenan entre ellos .Sin embargo si lo revisamos a detalle partiendo de que los Strings son objetos “Inmutables” nos daremos cuenta que se crean los siguientes objetos en memoria.
- “hola”
- “que”
- “tal”
- “estas”
- “tal estas”
- “que tal estas”
- “hola que tal estas”
Lo
Tenemos un pequeño problema ya que ya no son únicamente 4 objetos sino que son 7 .
Si realizamos el buble 10000 veces tendremos 70000 objetos en memoria . Ahora bien si miramos un poco mas a detalle nos daremos cuenta que todos estos objetos solo se crean una vez y luego se almacenan en un pool de “String” .
Así pues parece que al final solo tenemos 7 objetos en todo el buble . Sin embargo ¿como es que va tan lento? . Bueno realmente tenemos unicamente 7 objetos en la primera iteración del buble. Si pasamos a la segunda iteración nos encontraremos algo así.
StringBuffer un problema
Así que tenemos un objeto adicional mas que se genera. No parece mucho pero en un buble de 10000 son 10000 objetos nuevos (ya que todos son distintos) ademas de copiar el texto del objeto anterior al nuevo . Ahora si que podemos ver el problema de una forma bastante mas clara. Para solucionarlo en vez de usar en este buble un objeto de tipo String usaremos un StringBuffer o StringBuilder ambos nos ayudarán a solventar este problema.
package com.arquitecturajava; public class Principal02 { public static void main(String[] args) { StringBuffer cadena = new StringBuffer(); long numero1 = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { cadena.append("hola"); cadena.append("que"); cadena.append("tal"); cadena.append("estas"); } long numero2 = System.currentTimeMillis(); System.out.println(numero2 - numero1); } } }
StringBuffer una unica instancia
La diferencia fundamental es que el objeto StringBuffer se crea la primera vez y va acumulando el texto. Por lo tanto nos ahorraremos el crear 10000 objetos adicionales. Realizada la modificación nos encontraremos con que el rendimiento se dispara. En la mayoría de las ocasiones String funciona mejor que StringBuffer .Es en estas situaciones peculiares en las que el rendimiento es peor .
Hice un ejemplo utilizando el String,StringBuilder y StringBuffer y pues bueno
el StringBuilder es la clase intermedia entre String y StringBuffer.
Aqui el código
https://gist.github.com/ripper2hl/867df343cae0a72895ff
[…] artículos relacionados : StringBuilder, String y Rendimiento , foreach vs […]
Tampoco es el mejor ejemplo posible. O mucho me equivoco yo o al ver “hola” + “que” +”tal” +”estas”, el compilador genera un único literal “hola que tal estas”, igual que hace con operadores sobre literales numericos (el tipico 24 * 60 * 60)
Es decir, en el fondo lo que dices es cierto (y muy importante), pero el ejemplo puede no ser el mejor
Siempre se admiten nuevas ideas .Comenta alguna cosa complementaria Gonzalo .Gracias
En realidad, el compilador, cuando la concatenación es en una misma instruccion, usa StringBuilder (o buffer ahora no estoy seguro), por lo que la concatenación es igual de efectiva. Sin embargo, si la realizas en bucle, tendras un montón de stringbuilder ademas de los literales. Por eeo siempre es mejor especificar tu como se usa el builder. No obstante, para muchos casos es tontería usarlo, java lo hará por nosotros.
Muy clara tu explicación Cecilio. Conozco muchos programadores Java que desconocen este funcionamiento de los String, sin embargo, discrepo contigo en que String sea mejor en muchos casos. Me explico: String es mejor que StringBuffer o StringBuilder cuando el programa se ejecuta y termina. Por ejemplo un programa java lanzado desde un script. Sin embargo, concatenar Strings cuando el software se va a ejecutar dentro de un Servidor de aplicaciones (un servicio web que esté ejecutandose las 24 horas) va a suponer la creación de objetos extra que permanecerán en memoria hasta indefinidamente. En cualquier caso, muy buena tu explicación,… Read more »
gracias 🙂
Una cosa Cecilio, deberías corregir el ejercicio y poner en el ejemplo del stringbuffer , poner más appends en lugar de concatenar usando el “+”
Saludos.
Tienes toda la razon 🙂 gracias
Corregido