StringBuffer mejor que usar + …. cuidado!!!!
Publicado por robmv 9 Agosto 2006 en J2EE, Java.Frecuentemente he tenido que explicar porque no siempre usar StringBuffer es mejor que usar + para concatenar Strings en Java y esto porque existe la creencia que usar el operador + es siempre malo; esto no es cierto, veamos algunos ejemplos:
Sin importar la cantidad de veces que se ejecute o si esto esta en un ciclo de mil repeticiones, es mucho más rápido que ejecutar
-
buffer.append("11111");
-
buffer.append("22222");
-
buffer.append("3333");
¿por qué?, la respuesta es simple, el compilador. Desde hace mucho tiempo los compiladores Java son capaces de identificar los literales y los compactan de tal manera que la suma que se da como ejemplo, es almacenada en la clase compilada como un solo String. Si no tienen un decompilador a la mano de todos modos pueden confirmar abriendo el archivo .class en cualquier editor y notarán que aparece un solo String 111112222233333
Asi que cosas como esta no se deben hacer:
-
buffer.append("SELECT COL_A, COL_B, COL_C, COL_D, COL_E");
-
buffer.append(" FROM TABLA_A");
-
buffer.append(" WHERE COL_A> ?");
Tratando de optimizar con las reglas que tanto se repiten en las mejores prácticas, estamos dañando todo :-)
Tarea.. usar un decompilador sobre este código:
¿que observarán?, que el compilador introduce un StringBuffer automáticamente en el bytecode. OJO esto no significa que ahora van a ser super confiados con el +, principalmente cuando se está construyendo un String muy grande y hay ciclos en medio de todo.
Para mis amigos amantes Ruby, tengan cuidado siempre ya que les hace falta un compilador :-P... jeje
hola Robmv,
Muy bueno el articulo, pero no estoy de acuerdo con tu ejemplo ya que no es del todo correcto; Cuando tu escribes un SQL como ese, lo haces una vez y despues utilizar el "PreparedStatement" para reemplazar los "?". Como el SQL se escribe una sola vez, el costo de utilizar StringBuffer.append() y una simple concatenacion con "+" es mas o menos el mismo. El costo aqui es negligible comparado con el hecho de utilizar una concatenacion, lo que importa es que el codigo sea mantenible.
Quieres un ejemplo mas realista? Que pasa si tienes que construir un SQL mas complicado, dependiendo de condiciones externas al programa? Alli el uso de un objeto String para concatenar se hace tedioso, ademas de que Java comienza a gastar mas espacio pues cada una de esas cadenas se queda en cache hasta el el garbaGe collector las elimina (lo cual no es deterministico).
Deberias mencionar tambien que hay otras ocasiones en las cuales es importante el manejo de memoria, y es entonces que la clase StringBuffer se justifica, por algo la agregaron al lenguaje ;)
Saludos!
Hola KodeGeek, la idea era mostrar ese ejemplo exactamente , ¿por qué? porque el SQL formado por tres literales exactamente (literales = que son explicitamente indicados en el código), por lo que es falso lo que dices de que es ineligible en este caso usar un StringBuffer o +... Aclaro un poco, si usara un String buffer el JVM tendría que hacer lo siguiente:
1- Buscar la clase java.lang.StringBuffer
2- Invocar al contructor al instanciar el objecto
3- Invocar 3 veces al método append()
4- Invocar al método toString()
5- Asignar el valor a la variable resultado
en el caso de usar el operador + haria lo siguiente
1- Buscar el String "SELECT COL_A, COL_B, COL_C, COL_D, COL_E FROM TABLA_A WHERE COL_A > ?" en la definición de la clase (recuerda que el compilador lo concatenó y lo puso como un solo literal en el .class)
2- Asignar el valor a la variable resultado
El separar los SQLs en multiples lineas se hace con frecuencia solo por ayudar en la lectura del SQL ya que es mas facil leer
String sql = "SELECT COL_A, COL_B, COL_C, COL_D, COL_E" +
" FROM TABLA_A" +
" WHERE COL_A> ?";
que todo en una sola línea. Nunca mi intención fue decir nunca se debe usar el StringBuffer.... solo es un "CUIDADO" bien notorio a los errores que he visto con frecuencia, como este, concatenar puros literales con StringBuffer. te remito a loque escribí al final:
"OJO esto no significa que ahora van a ser super confiados con el +, principalmente cuando se está construyendo un String muy grande y hay ciclos en medio de todo."
Hola Robmv,
Sobre esto:
"1- Buscar la clase java.lang.StringBuffer
2- Invocar al contructor al instanciar el objecto
5- Asignar el valor a la variable resultado"
Para 1: El costo es negligible de nuevo, ya que una vez cargada la clase StringBuffer no hace falta hacerlo mas (asi que es un costo de una sola vez)
Para 2: La instancia del objeto StringBuffer dependiendo de la aplicacion en pocas palabras se puede recliclar (StringBuffer.setLength(0)). Si es un metodo largo o la aplicacion no requiere concurrencia, entonces quizas un Singleton resuelve el problema.
Para 5: Es una asignacion de una referencia, eso toma el mismo tiempo (no estas llamando a ningun constructor, no es asi?)
Como puedes ver eso de la velocidad depende mucho de la aplicacion, asi que no deberias ser tan rapido al generalizar :)
Saludos.
jejeje no estoy generalizando, el caso es muy especifico, son 3 literales... no hay nada dinamico alli.. siempre va a ser los mismos tres literales, no importa cuanta gente llame a ese método. Pero personalmente estoy 100% seguro que en este caso bien concreto, prefiero que mis colegas en el desarrollo usen + ya que si el método es de alto uso, digamos 100 request por segundo.. prefiero usar un solo literal unido por el compilador que 100 instancias creadas de StringBuffer con 4 invocaciones de métodos... OJO.. son literales no estoy hablando de armar un WHERE dinamicamente ni nada por el estilo :-P... alguien que opine para que nos quitemos los guantes .. jajajajaja
Para ver si me ayudo a explicar un poco más... sin pensar mucho en el orden de magnitud ni la concurrencia, que se ejecuta más rápido:
int numero = 1 + 5 * 8 * 2 * 129381923;
o
int numero = 10350553841;
la respuesta es sencilla.. tardan exactamente lo mismo, ya que los compiladores Java no generan las intrucciones para calcular "1 + 5 * 8 * 2 * 129381923" sino que lo calculan antes de generar el bytecode. Igual pasa con el caso analizado, tres literales preconcatenados por el compilador
Efectivamente si la idea es concatenar literales y el issues es el performance, el + puede se mejor opción que el uso de StringBuffer, inclusive yo agregaría que la variable en cuestion fuese estática:
Por otro lado el uso de StringBuffer se justifica más si cuando usamos el constructor le pasamos la longitud inicial del buffer, para que la "allocación" de memoria sea eficiente.
me podrias echar una alluda hice este codigo para leer archivos pero es muy lento para archivos muy grandes estuve leyendo y me encontre con un StringBuffer con esto segun lo leiria mas rapido pero no se como implementarlo me podrian decir como quedaria el codigo gracias...porfavor alludenme
import java.io.RandomAccessFile;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Visor{
private String archivo;
public Visor (String archivo){
this.archivo=archivo;
}
public String leer(){
RandomAccessFile raf;
String texto="";
try{
String linea = null;
raf = new RandomAccessFile(this.archivo, "r");
while((linea=raf.readLine())!=null){
texto=texto+linea+"\n";//concatenacion
}
raf.close();
}
catch(FileNotFoundException fnfe){
System.out.println("Archivo no econtrado");
}
catch(IOException ioe){
System.out.println("Error de I/O.");
}
return texto;
}
}
Estou procurando um decompilador para sql server. o programador sumiu e eu preciso fazer uns ajustes num sistema de patrimônio. se puderes me ajudar ficareio eternamente grato. atenciosamente,
Walter bento de Lima .´.
Totalmente de acuerdo, la concatenacion de string hoy por hoy no tiene influencia en los tiempos de ejecucion. el foco deberia estar puesto en lo mantenible que es el codigo generado.
http://gpitech.wordpress.com/
buenas
Y yo que ponía especial cuidado en usar StringBuffer... gracias por el post.