java performance readability

java - StringBuilder/StringBuffer vs. "+" Operador



string vs stringbuilder c# (4)

Considere la siguiente prueba de rendimiento, estamos construyendo una cadena dinámica dentro de un ciclo de iteración 100000:

public void constructDynamicString() { long startTime = System.currentTimeMillis(); String s = "test"; //StringBuffer s = new StringBuffer("test"); //StringBuilder s = new StringBuilder("test"); for(int i=0; i<100000; i++) { s += "concat"; //s.append("concat"); } long endTime = System.currentTimeMillis(); System.out.println("Concat time ====== " + (endTime - startTime)); }

Ejecutamos la prueba anterior 3 veces, cada enfoque a la vez, y obtenemos el siguiente resultado:

With String, it tooks: 39068 ms With StringBuffer, it tooks: 7ms With StringBuilder, it tooks: 4ms

A partir de los resultados anteriores, observamos que usar el objeto String para crear una cadena de caracteres dinámicos es mucho más lento que usar StringBuffer y StringBuilder debido al hecho de la inmutabilidad.

Además, StringBuilder es más rápido que StringBuffer, ya que no le importa la sincronización (aunque parece un poco más rápido, la velocidad sería relativamente diferente si aumentamos el número de iteraciones).

Ahora, para decidir qué clase usar, tenga en cuenta los siguientes factores:

  1. Si está creando una cadena de caracteres estáticos que no debe modificarse a lo largo del flujo del programa, utilice el objeto Cadena .
  2. Si está creando una cadena de caracteres dinámicos que debe compartirse entre varios hilos, considere usar StringBuffer .
  3. Si ambos factores no existen (que es un caso muy común), entonces use StringBuilder .

Fuente: StringBuilder VS StringBuffer

Estoy leyendo " Java mejor, más rápido, más ligero " (por Bruce Tate y Justin Gehtland) y estoy familiarizado con los requisitos de legibilidad en equipos de tipo ágil, como lo que Robert Martin discute en sus libros de código limpio. En el equipo en el que estoy ahora, se me ha dicho explícitamente que no use el operador + porque crea objetos de cadena adicionales (e innecesarios) durante el tiempo de ejecución.

Pero este article , escrito nuevamente en ''04, habla de cómo la asignación de objetos es aproximadamente 10 instrucciones de la máquina. (esencialmente gratis)

También habla sobre cómo el GC también ayuda a reducir los costos en este entorno.

¿Cuál es la compensación de rendimiento real entre usar + , StringBuilder o StringBuffer ? (En mi caso, es StringBuffer solo porque estamos limitados a Java 1.4.2.)

StringBuffer para mí da como resultado un código feo y menos legible, como lo demuestran un par de ejemplos en el libro de Tate. Y StringBuffer está sincronizado con subprocesos que parece tener sus propios costos que superan el "peligro" al usar el operador + .

Pensamientos / Opiniones


La utilización de String concatenación de String se traduce en operaciones StringBuilder por el compilador.

Para ver cómo funciona el compilador tomaré una clase de muestra, la compilaré y la descompilaré con jad para ver cuál es el bytecode generado.

Clase original:

public void method1() { System.out.println("The answer is: " + 42); } public void method2(int value) { System.out.println("The answer is: " + value); } public void method3(int value) { String a = "The answer is: " + value; System.out.println(a + " what is the question ?"); }

La clase descompilada

public void method1() { System.out.println("The answer is: 42"); } public void method2(int value) { System.out.println((new StringBuilder("The answer is: ")).append(value).toString()); } public void method3(int value) { String a = (new StringBuilder("The answer is: ")).append(value).toString(); System.out.println((new StringBuilder(String.valueOf(a))).append(" what is the question ?").toString()); }

  • En method1 el compilador realizó la operación en tiempo de compilación.
  • En method2 la concatenación de String equivale a usar manualmente StringBuilder .
  • En method3 la concatenación String es definitivamente mala ya que el compilador está creando un segundo StringBuilder lugar de reutilizar el anterior.

Así que mi regla simple es que las concatenaciones son buenas a menos que necesites concatenar el resultado nuevamente: por ejemplo, en bucles o cuando necesitas almacenar un resultado intermedio.


Para concatenaciones pequeñas, puede simplemente usar String y + en aras de la legibilidad. El rendimiento no va a sufrir. Pero si está realizando muchas operaciones de concatenación, vaya a StringBuffer.


Su equipo necesita conocer las razones para evitar la concatenación repetida de cadenas .

Ciertamente hay momentos en los que tiene sentido usar StringBuffer , en particular cuando está creando una cadena en un bucle, especialmente si no está seguro de que habrá pocas iteraciones en el ciclo. Tenga en cuenta que no solo se trata de crear objetos nuevos; se trata de copiar todos los datos de texto que ya ha agregado. También tenga en cuenta que la asignación de objetos solo es "esencialmente gratuita" si no considera la recolección de basura. Sí, si hay suficiente espacio en la generación actual, básicamente se trata de incrementar un puntero ... pero:

  • Esa memoria debe haberse borrado en algún momento. Eso no es gratis.
  • Estás acortando el tiempo hasta que se requiera el próximo GC. GC no es gratis.
  • Si su objeto vive en la próxima generación, puede llevar más tiempo limpiarlo, nuevamente, no gratis.

Todas estas cosas son razonablemente económicas ya que "por lo general" no vale la pena desviar un diseño de la elegancia para evitar la creación de objetos ... pero no debería considerarlos como gratuitos .

Por otro lado, no tiene sentido utilizar StringBuffer en los casos en que no necesite las cadenas intermedias. Por ejemplo:

String x = a + b + c + d;

es al menos tan eficiente como:

StringBuffer buffer = new StringBuffer(); buffer.append(a); buffer.append(b); buffer.append(c); buffer.append(d); String x = buffer.toString();