2011-09-28 21 views
47

Según Netbeans HinT nombrado Uso cadena de métodos .Append en lugar de la concatenación de cadenas¿La cadena de StringBuilder.append es más eficiente que la concatenación de cadenas?

busca la concatenación de cadenas en el parámetro de una invocación del método append de StringBuilder o StringBuffer.

¿Es StringBuilder.append() realmente más eficiente que la concatenación de cadenas?

Ejemplo de código

StringBuilder sb = new StringBuilder(); 
sb.append(filename + "/"); 

vs

StringBuilder sb = new StringBuilder(); 
sb.append(filename).append("/"); 
+0

Echa un vistazo a esta interesante lectura: http://www.precisejava.com/javaperf/j2se/StringAndStringBuffer.htm – Zaki

+1

@Zaki: Esos puntos de referencia no son realmente tan útiles en términos prácticos. Lo que es más útil es perfilar su aplicación para ver si realmente tiene un cuello de botella de rendimiento. Y elegir los algoritmos apropiados y las estructuras de datos para su caso de uso particular. – mellamokb

Respuesta

69

Hay que equilibrar la legibilidad y funcionalidad.

Digamos que usted tiene lo siguiente:

String str = "foo"; 
str += "bar"; 
if(baz) str += "baz"; 

Esto creará 2 constructores de cadena (en la que sólo necesita 1, en realidad) más un objeto de cadena adicional para el ínterin. Usted sería más eficiente si se fue:

StringBuilder strBuilder = new StringBuilder("foo"); 
strBuilder.append("bar"); 
if(baz) strBuilder.append("baz"); 
String str = strBuilder.toString(); 

embargo, como cuestión de estilo, creo que la primera de ellas se ve muy bien. El beneficio de rendimiento de la creación de un solo objeto parece muy mínimo para mí.Ahora, si en lugar de 3 cuerdas, tuvieras 10, o 20, o 100, diría que el rendimiento supera el estilo. Si estuviera en un bucle, seguro usaría el generador de cadenas, pero creo que solo un par de cadenas está bien para hacer la manera 'descuidada' de hacer que el código se vea más limpio. Pero ... ¡esto tiene una trampa muy peligrosa al acecho! Lea a continuación (pausa para crear suspenso ... dun dun dunnnn)

Hay quienes dicen que siempre use el generador de cadenas explícito. Una de las razones es que su código seguirá creciendo, y generalmente lo hará de la misma manera que ya lo está (es decir, no se tomarán el tiempo para refactorizar). Así que terminará con esas 10 o 20 declaraciones cada una de ellas creando su propio constructor cuando no es necesario. Para evitar esto desde el principio, dicen que siempre usan un constructor explícito.

Por lo tanto, en su ejemplo, no va a ser particularmente rápido, cuando alguien en el futuro decide que quiere una extensión de archivo al final, o algo así, si continúa utilizando la concatenación de cadenas en lugar de un StringBuilder, finalmente se encontrarán con problemas de rendimiento.

También tenemos que pensar en el futuro. Digamos que usted hacía atrás en el código Java JDK 1.1 y que tenía el siguiente método:

public String concat(String s1, String s2, String s3) { 
    return s1 + s2 + s3; 
} 

En ese momento, habría sido lento debido a StringBuilder no existiera.

Luego, en JDK 1.3 decidiste hacerlo más rápido usando StringBuffer (StringBuilder todavía no existe). Esto se hace:

public String concat(String s1, String s2, String s3) { 
    StringBuffer sb = new StringBuffer(); 
    sb.append(s1); 
    sb.append(s2); 
    sb.append(s3); 
    return sb.toString(); 
} 

Se vuelve mucho más rápido. ¡Increíble!

Ahora JDK 1.5 que sale, y con él viene StringBuilder (que es más rápido que StringBuffer) y el transation automática de

return s1 + s2 + s3; 

a

return new StringBuilder().append(s1).append(s2).append(s3).toString(); 

Pero usted no recibe esta actuación beneficio porque estás usando StringBuffer explícitamente. Entonces, al ser inteligente, has causado un golpe de rendimiento cuando Java se volvió más inteligente que tú. Así que debes tener en cuenta que hay cosas por las que no pensarás.

+0

@corsiKa: Mi ciclo se ejecuta 16 veces y esto es lo que estoy haciendo en el ciclo - str + = som_value. El mío es jdk1.6. Entonces debería usar StringBuilder o no. – Ashwin

+0

@Ashwin Usaría StringBuilder allí, personalmente. ¿Es necesario? Supongo que depende de la frecuencia con que se ejecute el bucle. Si está creando el resultado de un hash, entonces puede esperar hacer eso mucho. Definitivamente acelerarlo. Si está creando el título de su programa y solo se llama una vez, probablemente no sea tan importante. – corsiKa

2

es sólo más eficiente si está utilizando una gran cantidad de concatenación y cadenas muy largas. Para uso general, como crear un nombre de archivo en su ejemplo, cualquier concatenación de cadenas es sencilla y más legible.

En cualquier caso, es poco probable que esta parte de su aplicación sea el cuello de botella de rendimiento.

+1

+1 pero el objeto StringBuilder creo que siempre se creó – gd1

10

Bueno, el primer ejemplo se traduce esencialmente por el compilador en algo a lo largo de las líneas:

StringBuilder sb = new StringBuilder(); 
sb.append(new StringBuilder().append(filename).append("/").toString()); 

así que sí, hay una cierta ineficiencia aquí. Sin embargo, si realmente importa en su programa es una pregunta diferente. Además de ser un estilo cuestionable (pista: subjetiva), por lo general solo importa, si estás haciendo esto en un círculo cerrado.

+0

¿La concatenación de cadenas realmente se hace usando un 'StringBuilder'? Parecería mucho más sensato tener 'String' que incluya un constructor que acepte dos cadenas y las concatene (posiblemente también tenga versiones para 3-4 cadenas, y una que tome' String [] '). Teniendo en cuenta las cadenas a concatenar, uno podría agregar sus longitudes antes de asignar espacio para la tienda de respaldo del resultado, y así asignar la cantidad exacta de espacio de una sola vez. Parecería loco que el compilador no hiciera eso. – supercat

2

Teóricamente, sí. Porque los objetos String son inmutables: una vez construidos, ya no se pueden cambiar. Entonces, usar "+" (concatenación) básicamente crea un nuevo objeto cada vez.

Prácticamente no. El compilador es lo suficientemente inteligente como para reemplazar todo su "+" con anexos de StringBuilder.

Para una explicación más detallada: http://kaioa.com/node/59

PS: Netbeans ??? ¡Venga!

+0

'¡Vamos!'? ¿Qué recomendarías entonces? –

+0

Su segunda oración implica que están todos puestos en un StringBuilder. Esto es inexacto. Si tiene 'String s =" a "+" b "; s + = "c"; 'obtendrá 2 constructores de cadenas, no 1. – corsiKa

+1

Recomendaría intelliJ o Eclipse – Guillaume

2

Un concat de dos cadenas es más rápido con esta función.

Sin embargo, si tiene varias cuerdas o diferente tipo de datos, se debe utilizar un StringBuilder ya sea explícita o implícitamente. Usar un + con Strings está usando StringBuilder implícitamente.

5

Ninguna de las respuestas hasta el momento aborda explícitamente el caso específico para el que está la pista. No está diciendo a siempre use StringBuilder#append en lugar de concatenación. Pero, si ya está usando un StringBuilder, no tiene sentido mezclar en concatenación, porque crea un StringBuilder redundante (consulte Dirk's answer) y una instancia temporal innecesaria de String.

Varias respuestas ya explican por qué la forma sugerida es más eficiente, pero el punto principal es que si ya tiene una instancia StringBuilder, simplemente llame al append. Es igual de fácil de leer (en mi opinión, y al parecer, quien escribió la sugerencia de NetBeans) ya que está llamando al append de todos modos, y es un poco más eficiente.

+0

Hay potencialmente algunos casos donde hacer la concatenación primero sería beneficioso; la mayoría de estos son escenarios donde, si las cadenas tuvieran algunas variaciones aleatorias en sus longitudes, la probabilidad de que la pre-concatenación sea más eficiente sería bastante baja, pero con algunas combinaciones particulares de longitudes de cuerdas podría "ganar" cada vez. Si el primer 'Append' expandiría' StringBuilder'/'StringBuffer' a un tamaño insuficiente para acomodar el segundo, la asignación adicional causada por la concatenación podría ser menos costosa que la utilizada por el SB. Un escenario raro, pero posible. – supercat

+0

@supercat Ese es un punto interesante, y un buen ejemplo de por qué siempre debes medir cuando estás optimizando el código (y usar datos representativos). –

+1

Mi propia preferencia sería recurrir a mi regla principal: "hacer lo que tiene sentido". En la mayoría de los casos, no es probable que exista una gran diferencia de rendimiento de ninguna manera, por lo que debe favorecerse la concatenación cuando sea más clara y no afecte notablemente el rendimiento. En los casos en que deben ocurrir múltiples concatenaciones en diferentes declaraciones, prefiero 'StringBuilder', pero cuando pueden aparecer en una expresión, prefiero eso. A menos que las cadenas sean grandes, la legibilidad debería ser una prioridad más alta que el rendimiento. – supercat

Cuestiones relacionadas