Alguien me dijo que es más eficiente usar StringBuffer
para concatenar cadenas en Java que utilizar el operador +
para String
s. ¿Qué pasa debajo del capó cuando haces eso? ¿Qué hace StringBuffer
de manera diferente?por qué utilizar StringBuffer en Java en lugar del operador de concatenación de cadenas
Respuesta
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.
Explicación muy clara, gracias –
Al final dices "esto es costoso", pero no apuntaste a otra forma de hacerlo, como cambiar la instrucción FOR tal vez ... – user1156544
@ user1156544 What sería una mejor forma de concatenar cadenas en una matriz? – user3932000
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.
¿Está seguro de que no es Cadena x1 = StringBuffer(). Añada ("a"). ToString(); Cadena x2 = StringBuffer (x1) .append ("b"). ToString(); y así sucesivamente? – Stroboskop
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
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.
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 .
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.
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.
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.
¿Por qué el compilador no puede optimizar esto? Parece que el compilador debería ser capaz de resolver esto. –
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.
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.
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.
Creo que la respuesta más simple es: es más rápido.
Si realmente quieres saber todo lo que hay debajo del capó, siempre se puede echar un vistazo a la fuente sí mismo:
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.
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.
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 .
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.
Supongo que "a" + "b" + "c" se compilará en "abc" directamente, sin concatenación de cadenas en tiempo de ejecución. – Thilo
@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
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";
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):
- construir un objeto de cadena de longitud 1, y el valor "x"
- Crear un nuevo objeto de cadena de tamaño 2, copie la vieja cadena "x" en ella, agregue "x" en la posición 2.
- Cree un nuevo objeto de cadena de tamaño 3, copie la cadena "xx" anterior, agregue "x" en la posición 3.
- ... 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.
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 ..
}
Aunque la información aquí es correcta, ¡no está respondiendo la pregunta! ¡Entonces no debería ser agregado como una respuesta! –
- 1. Java: StringBuffer y concatenación
- 2. Eficiencia de concatenación de cadenas de Java
- 3. Hacer un operador de concatenación de cadenas en R
- 4. Concatenación de cadenas mediante el operador '+'
- 5. Concatenación de cadenas y Autoboxing en Java
- 6. Concatenación de cadenas en EL
- 7. ¿Qué tan ineficiente es la concatenación de cadenas en Javascript?
- 8. StringBuilder/StringBuffer vs. "+" Operador
- 9. concatenación de cadenas
- 10. ¿Cuándo debería usar String.Format o String.Concat en lugar del operador de concatenación?
- 11. Operador ternario y peculiaridad de concatenación de cadenas?
- 12. ¿Por qué utilizar TagBuilder en lugar de StringBuilder?
- 13. ¿Por qué funciona + con cadenas en Java?
- 14. Concatenación de cadenas en Jinja
- 15. Concatenación de cadenas en Lua
- 16. ¿Por qué utilizar un operador de tubería hacia atrás en lugar de cadena de funciones?
- 17. ¿Por qué el operador% se conoce como el operador "módulo" en lugar del operador "restante"?
- 18. ¿Por qué permitir la concatenación de cadenas literales?
- 19. Concatenación de cadenas en MySQL
- 20. Cadenas de concatenación en Menos
- 21. ¿Qué colección utilizar en lugar de matriz 2D en Java?
- 22. Concatenación de cadenas PHP
- 23. Operador de concatenación + o,
- 24. operador de concatenación (+) frente concat()
- 25. ¿Por qué obtengo resultados diferentes al comparar cadenas después de usar una concatenación diferente en Java?
- 26. ¿Por qué utilizar jQuery en() en lugar de clic()
- 27. Concatenación de cadenas en Java: cuándo usar +, StringBuilder y concat
- 28. Cadenas de concatenación en JSP EL?
- 29. Cadenas de concatenación con
- 30. Cadenas de concatenación en macros - C++
Por favor, pasar un poco de tiempo y haz que tus publicaciones sean un poco más legibles. – GEOCHET
también es válido en C# –