2008-09-15 20 views

Respuesta

19

Uno no debe ser más rápido que el otro. Esto no era cierto antes de Java 1.4.2, porque al concatenar más de dos cadenas usando el operador "+", los objetos intermedios String se crearían durante el proceso de construcción de la cadena final.

Sin embargo, como los estados JavaDoc for StringBuffer, al menos desde Java 1.4.2 utilizando el operador "+" compila a la creación de un StringBuffer y append() ing las muchas cadenas a ella. Entonces no hay diferencia, al parecer.

Sin embargo, tenga cuidado al usar la adición de una cadena a otra dentro de un bucle! Por ejemplo:

String myString = ""; 

for (String s : listOfStrings) { 
    // Be careful! You're creating one intermediate String object 
    // for every iteration on the list (this is costly!) 
    myString += s; 
} 

tener en cuenta, sin embargo, que por lo general la concatenación de algunos hilos con "+" es más limpio que append() ing a todos.

+0

Explicación muy clara, gracias –

+0

Al final dices "esto es costoso", pero no apuntaste a otra forma de hacerlo, como cambiar la instrucción FOR tal vez ... – user1156544

+0

@ user1156544 What sería una mejor forma de concatenar cadenas en una matriz? – user3932000

9

Bajo el capó, lo que realmente crea y añade a un StringBuffer, llamar a toString() en el resultado. Por lo tanto, en realidad ya no importa que uses.

Así

String s = "a" + "b" + "c"; 

convierte

String s = new StringBuffer().append("a").append("b").append("c").toString(); 

Eso es cierto para un montón de inline anexa dentro de un solo estado. Si construye su cadena en el transcurso de múltiples instrucciones, entonces está desperdiciando memoria y un StringBuffer o StringBuilder es su mejor opción.

+1

¿Está seguro de que no es Cadena x1 = StringBuffer(). Añada ("a"). ToString(); Cadena x2 = StringBuffer (x1) .append ("b"). ToString(); y así sucesivamente? – Stroboskop

+4

Eso no es verdad. Las concatenaciones de String * literales * en realidad se optimizarán a un solo literal (al menos por javac de Sun desde JDK 1.4.) StrinBuffer se usa si no todas las expresiones son literales de cadena. – sleske

0

Debido a que las cadenas son imutable en Java, cada vez que concanate una cadena, nuevo objeto se crea en la memoria. SpringBuffer usa el mismo objeto en la memoria.

1

StringBuffer es mutable. Agrega el valor de la cadena al mismo objeto sin instanciar otro objeto. Hacer algo como:

myString = myString + "XYZ" 

creará un nuevo objeto String .

3

Java convierte cadena1 + cadena2 en un StringBuffer construir, append(), y toString(). Esto tiene sentido.

Sin embargo, en Java 1.4 y anteriores, sería hacer esto para cada operador + en la declaración por separado . Esto significaba que hacer a + b + c resultaría en dos StringBuffer construye con dos toString() llama. Si tuvieras una larga cadena de concats, se convertiría en un verdadero desastre. Hacerlo usted mismo significaba que podía controlar esto y hacerlo correctamente.

Java 5.0 y superiores parecen hacerlo más sensible, por lo que es menos de un problema y es ciertamente menos detallado.

1

Para concatenar dos cadenas usando '+', se debe asignar una nueva cadena con espacio para ambas cadenas, y luego los datos copiados de ambas cadenas. Un StringBuffer está optimizado para concatenar, y asigna más espacio de lo necesario inicialmente. Cuando concatena una nueva cadena, en la mayoría de los casos, los caracteres simplemente pueden copiarse al final del búfer de cadena existente.
Para concatenar dos cadenas, el operador '+' probablemente tendrá menos sobrecarga, pero a medida que concatene más cadenas, el StringBuffer saldrá adelante, utilizando menos asignaciones de memoria y menos copia de datos.

58

Es mejor utilizar StringBuilder (que es una versión no sincronizado, cuando se construye cadenas en paralelo?) En estos días, en casi todos los casos, pero esto es lo que sucede:

Cuando se utiliza + con dos cadenas, se compila código como este:

String third = first + second; 

para algo como esto:

StringBuilder builder = new StringBuilder(first); 
builder.append(second); 
third = builder.toString(); 

tanto por tan sólo pequeños ejemplos, por lo general no hace diferen ce. Pero cuando construyes una cadena compleja, a menudo tienes que lidiar con mucho más que esto; por ejemplo, es posible que el uso de muchos estados diferentes anexar, o un bucle de esta manera:

for(String str : strings) { 
    out += str; 
} 

En este caso, un nuevo StringBuilder ejemplo, y un nuevo String (el nuevo valor de out - String s son inmutables) es requerido en cada iteración. Esto es muy derrochador Reemplazar esto con un solo StringBuilder significa que puede simplemente producir un solo String y no llenar el montón con String s que no le importa.

+6

¿Por qué el compilador no puede optimizar esto? Parece que el compilador debería ser capaz de resolver esto. –

1

La clase StringBuffer mantiene una matriz de caracteres para contener los contenidos de las cadenas que concatenas, mientras que el método + crea una nueva cadena cada vez que se invoca y agrega los dos parámetros (param1 + param2).

StringBuffer es más rápido porque 1. podría usar su matriz ya existente para concat/almacenar todas las cadenas. 2. Incluso si no caben en la matriz, es más rápido asignar una matriz de respaldo más grande y luego generar nuevos objetos de cadena para cada evocación.

7

creo que jdk1.5 dado (o superior) y su concatenación es seguro para subprocesos que debe utilizar StringBuilder en lugar de StringBuffer http://java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs-stringbuilder.html En cuanto a los aumentos en la velocidad: http://www.about280.com/stringtest.html

Personalmente me código para facilitar la lectura, a menos que descubra que la concatenación de cadenas hace que su código sea considerablemente más lento, quédese con el método que haga que su código sea más legible.

1

Dado que las cadenas son inmutables, cada llamada al operador + crea un nuevo objeto String y copia los datos de Cadena en la nueva Cadena. Como copiar una cadena lleva tiempo lineal en la longitud de la cadena, una secuencia de N llamadas al operador + da como resultado O (N) tiempo de ejecución (cuadrático).

Por el contrario, como un StringBuffer es mutable, no necesita copiar el String cada vez que realiza un Append(), por lo que una secuencia de N Append() llama a O (N) time (linear). Esto solo hace una diferencia significativa en el tiempo de ejecución si está agregando una gran cantidad de cadenas juntas.

1

Como se ha dicho, el objeto String es ummutable, lo que significa que una vez creado (ver a continuación) no se puede cambiar.

Cadena x = new Cadena ("algo"); // o

Cadena x = "algo";

Así que cuando intentas concatenar objetos String, el valor de esos objetos se toma y se pone en un nuevo objeto String.

Si en su lugar usa StringBuffer, que es mutable, agrega continuamente los valores a una lista interna de caracteres (primitivos), que pueden ampliarse o truncarse para ajustarse al valor necesario. No se crean nuevos objetos, solo se crean/eliminan nuevos caracteres cuando es necesario para mantener los valores.

0

La sección String Concatenation Operator + de la Especificación del lenguaje Java proporciona más información de contexto sobre por qué el operador + puede ser tan lento.

1

Cuando concatena dos cadenas, en realidad crea un tercer objeto String en Java. Usar StringBuffer (o StringBuilder en Java 5/6) es más rápido porque usa una matriz interna de caracteres para almacenar la cadena, y cuando usas uno de sus métodos de agregar (...), no crea una nueva cadena. objeto. En cambio, StringBuffer/Buider agrega la matriz interna.

En concatenaciones simples, no es realmente un problema si concatenas cadenas utilizando StringBuffer/Builder o el operador '+', pero al hacer muchas concatenaciones de cadenas, verás que usar StringBuffer/Builder es mucho más rápido .

40

Para concatenaciones simples como:

String s = "a" + "b" + "c"; 

Es bastante inútil utilizar StringBuffer - como jodonnell señaló que será traducido inteligentemente en:

String s = new StringBuffer().append("a").append("b").append("c").toString(); 

PERO es muy no es capaz de concatenar cadenas en un bucle, como:

String s = ""; 
for (int i = 0; i < 10; i++) { 
    s = s + Integer.toString(i); 
} 

El uso de una cadena en este ciclo generará 10 objetos de cadena intermedios en la memoria: "0", "01", "012" y así sucesivamente. Mientras escribía el mismo usando StringBuffer sólo tiene que actualizar algunos buffer interno de StringBuffer y no crear esos objetos de cadena intermedios que no necesitas:

StringBuffer sb = new StringBuffer(); 
for (int i = 0; i < 10; i++) { 
    sb.append(i); 
} 

realidad para el ejemplo anterior se debe utilizar StringBuilder (introducido en Java 1.5) en lugar de StringBuffer - StringBuffer es un poco más pesado ya que todos sus métodos están sincronizados.

+12

Supongo que "a" + "b" + "c" se compilará en "abc" directamente, sin concatenación de cadenas en tiempo de ejecución. – Thilo

+4

@Thilo: Sí, la mayoría de los compiladores de Java combinan concatenaciones de literales de cadenas con un solo literal. Ver p. http://nicklothian.com/blog/2005/06/09/on-java-string-concatenation/ – sleske

2

AFAIK depende de la versión de JVM, en las versiones anteriores a la 1.5 con "+" o "+ =" en realidad se copió toda la cadena cada vez.

Tenga en cuenta que usar + = en realidad asigna la nueva copia de la cadena.

Como se señaló utilizando bucles + in implica la copia.

Cuando cadenas que se conactenated son constantes de tiempo de compilación no concatenadas en tiempo de compilación, por lo

String foo = "a" + "b" + "c"; 

tiene es compilado a:

String foo = "abc"; 
5

En algunos casos esto es obsoleto debido a las optimizaciones realizadas por el compilador, pero el problema general es ese código como:

string myString=""; 
for(int i=0;i<x;i++) 
{ 
    myString += "x"; 
} 

actuará como abajo (cada paso de ser la siguiente iteración de bucle):

  1. construir un objeto de cadena de longitud 1, y el valor "x"
  2. Crear un nuevo objeto de cadena de tamaño 2, copie la vieja cadena "x" en ella, agregue "x" en la posición 2.
  3. Cree un nuevo objeto de cadena de tamaño 3, copie la cadena "xx" anterior, agregue "x" en la posición 3.
  4. ... y así sucesivamente

Como puede ver, cada iteración tiene que copiar en e más personaje, lo que nos lleva a realizar 1 + 2 + 3 + 4 + 5 + ... + N operaciones en cada ciclo. Esta es una operación O (n^2). Sin embargo, si supiéramos de antemano que solo necesitábamos N caracteres, podríamos hacerlo en una única asignación, con una copia de solo N caracteres de las cuerdas que estábamos usando, una mera operación O (n).

StringBuffer/StringBuilder evítelo porque son mutables, por lo que no es necesario seguir copiando los mismos datos una y otra vez (siempre que haya espacio para copiarlos en su búfer interno). Evitan realizar una asignación y una copia proporcional al número de anexos realizados al sobreasignar su memoria intermedia en una proporción de su tamaño actual, agregando O (1) amortizado.

Sin embargo, vale la pena señalar que a menudo el compilador será capaz de optimizar el código en el estilo de StringBuilder (o mejor, ya que puede realizar el plegado constante, etc.) de forma automática.

1

Más información:

StringBuffer es un hilo de seguridad de clase


public final class StringBuffer extends AbstractStringBuilder 
    implements Serializable, CharSequence 
{ 
// .. skip .. 
    public synchronized StringBuffer append(StringBuffer stringbuffer) 
    { 
     super.append(stringbuffer); 
     return this; 
    } 
// .. skip .. 
} 

Pero StringBuilder no es seguro para subprocesos, por lo que es más rápido usar StringBuilder si es posible


public final class StringBuilder extends AbstractStringBuilder 
    implements Serializable, CharSequence 
{ 
// .. skip .. 
    public StringBuilder append(String s) 
    { 
     super.append(s); 
     return this; 
    } 
// .. skip .. 
} 

+3

Aunque la información aquí es correcta, ¡no está respondiendo la pregunta! ¡Entonces no debería ser agregado como una respuesta! –

Cuestiones relacionadas