Dadas las 2 toString()
implementaciones a continuación, cuál es la preferida:
public String toString(){
return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}
o
public String toString(){
StringBuilder sb = new StringBuilder(100);
return sb.append("{a:").append(a)
.append(", b:").append(b)
.append(", c:").append(c)
.append("}")
.toString();
}
?
Más importante aún, dado que solo tenemos 3 propiedades, podría no hacer la diferencia, pero ¿en qué punto cambiaría de +
concat a StringBuilder
?
java
performance
string
concatenation
stringbuilder
no secuestrador
fuente
fuente
StringBuilder
cuánto tamaño asignar por adelantado, de lo contrario, si se queda sin espacio, tendrá que duplicar el tamaño creando un nuevachar[]
matriz luego copia los datos, lo cual es costoso. Puede hacer trampas dando el tamaño y luego no hay necesidad de esta creación de matriz, por lo que si cree que su cadena tendrá ~ 100 caracteres de largo, puede configurar el StringBuilder a ese tamaño y nunca tendrá que expandirse internamente.Respuestas:
La versión 1 es preferible porque es más corta y , de hecho, el compilador la convertirá en la versión 2 , sin ninguna diferencia de rendimiento.
En el punto en el que estás concatenando en un bucle, generalmente es cuando el compilador no puede sustituirlo
StringBuilder
por sí mismo.fuente
To increase the performance of repeated string concatenation, a Java compiler _may_ use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.
La palabra clave que exista mayo . Dado que esto es oficialmente opcional (aunque probablemente implementado), ¿no deberíamos protegernos?La clave es si está escribiendo una concatenación única en un solo lugar o acumulándola con el tiempo.
Para el ejemplo que diste, no tiene sentido usar explícitamente StringBuilder. (Mire el código compilado para su primer caso).
Pero si está creando una cadena, por ejemplo, dentro de un bucle, use StringBuilder.
Para aclarar, suponiendo que hugeArray contiene miles de cadenas, código como este:
consume mucho tiempo y memoria en comparación con:
fuente
result += s;
(en el primer ejemplo)"{a:"+ a + ", b:" + b + ", c: " + c +"}";
Yo prefiero:
... porque es corto y legible.
Yo no optimizar este para la velocidad a menos que lo utilice dentro de un bucle con un alto número de repeticiones y de haber medido la diferencia de rendimiento.
Estoy de acuerdo en que si tiene que generar muchos parámetros, este formulario puede ser confuso (como dice uno de los comentarios). En este caso, cambiaría a una forma más legible (quizás usando ToStringBuilder de apache-commons, tomado de la respuesta de matt b) e ignoraría el rendimiento nuevamente.
fuente
null
En la mayoría de los casos, no verá una diferencia real entre los dos enfoques, pero es fácil construir el peor de los casos como este:
El resultado es:
El problema es que a + = agregar a una cadena reconstruye una nueva cadena, por lo que cuesta algo lineal a la longitud de sus cadenas (suma de ambas).
Entonces, a su pregunta:
El segundo enfoque sería más rápido, pero es menos legible y más difícil de mantener. Como dije, en su caso específico probablemente no vería la diferencia.
fuente
+=
, el ejemplo original era una secuencia de+
que el compilador se transforma en una solastring.concat
llamada. Sus resultados no aplican.También tuve un conflicto con mi jefe sobre el hecho de si usar append o +. Como están usando Append (todavía no puedo entender como dicen cada vez que se crea un nuevo objeto). Así que pensé en hacer un poco de I + D. Aunque me encanta la explicación de Michael Borgwardt, pero solo quería mostrar una explicación si alguien realmente necesita saber en el futuro.
y el desmontaje de la clase anterior sale como
De los dos códigos anteriores, puede ver que Michael tiene razón. En cada caso, solo se crea un objeto SB.
fuente
Desde Java 1.5, la concatenación simple de una línea con "+" y StringBuilder.append () generan exactamente el mismo bytecode.
Entonces, en aras de la legibilidad del código, use "+".
2 excepciones:
fuente
Usando la última versión de Java (1.8), el desensamblaje (
javap -c
) muestra la optimización introducida por el compilador.+
asísb.append()
generará un código muy similar. Sin embargo, valdrá la pena inspeccionar el comportamiento si lo estamos usando+
en un ciclo for.Agregar cadenas usando + en un bucle for
Java:
ByteCode :(
for
extracto del bucle)Agregar cadenas usando stringbuilder.append
Java:
ByteCdoe :(
for
extracto del bucle)Sin embargo, hay una diferencia notable. En el primer caso, donde
+
se usó,StringBuilder
se crea nuevo para cada iteración de bucle y el resultado generado se almacena haciendo unatoString()
llamada (29 a 41). Por lo tanto, está generando cadenas intermedias que realmente no necesita mientras usa el+
operador enfor
bucle.fuente
En Java 9, la versión 1 debería ser más rápida porque se convierte en
invokedynamic
llamada. Se pueden encontrar más detalles en JEP-280 :fuente
Por razones de rendimiento, se desaconseja el uso de
+=
(String
concatenación). La razón es que: JavaString
es inmutable, cada vez que se realiza una nueva concatenación, seString
crea una nueva (la nueva tiene una huella digital diferente de la anterior que ya está en el conjunto de cadenas ). Crear nuevas cadenas ejerce presión sobre el GC y ralentiza el programa: la creación de objetos es costosa.El siguiente código debería hacerlo más práctico y claro al mismo tiempo.
Los resultados de una carrera se informan a continuación.
Sin considerar los resultados para 1 concatenación (JIT aún no estaba haciendo su trabajo), incluso para 10 concatenaciones la penalización de rendimiento es relevante; Para miles de concatenaciones, la diferencia es enorme.
Lecciones aprendidas de este experimento muy rápido (fácilmente reproducible con el código anterior): nunca use el
+=
para concatenar cadenas juntas, incluso en casos muy básicos donde se necesitan algunas concatenaciones (como se dijo, crear nuevas cadenas es costoso de todos modos y ejerce presión sobre el GC).fuente
Vea el siguiente ejemplo:
Salida:
A medida que aumenta la longitud de la cuerda, también lo hace el tiempo de concatenación.
Ahí es donde
StringBuilder
definitivamente se necesita.Como puede ver, la concatenación:
UUID.randomUUID()+"---"
realmente no afecta el tiempo.PD: No creo que usar StringBuilder en Java sea realmente un duplicado de esto.
Esta pregunta habla de
toString()
que la mayoría de las veces no realiza concatenaciones de cadenas enormes.Actualización 2019
Desde
java8
tiempos, las cosas han cambiado un poco. Parece que ahora (java13), el tiempo de concatenación de+=
es prácticamente el mismo questr.concat()
. Sin embargo, elStringBuilder
tiempo de concatenación sigue siendo constante . (La publicación original anterior fue ligeramente editada para agregar una salida más detallada)Vale la pena señalar que también la
bytecode:8/java.version:13
combinación tiene un buen rendimiento en comparación conbytecode:8/java.version:8
fuente
java13
que ahora son diferentes. Pero creo que la conclusión principal sigue siendo la misma.Apache Commons-Lang tiene una clase ToStringBuilder que es súper fácil de usar. Hace un buen trabajo al manejar la lógica de apéndice y al formatear cómo desea que se vea su toString.
Devolverá la salida que se parece
com.blah.YourClass@abc1321f[a=whatever, b=foo]
.O en una forma más condensada usando encadenamiento:
O si desea utilizar la reflexión para incluir todos los campos de la clase:
También puede personalizar el estilo de ToString si lo desea.
fuente
¡Haga que el método toString sea lo más legible posible!
La única excepción para esto en mi libro es si puedes demostrarme que consume recursos significativos :) (Sí, esto significa perfilar)
También tenga en cuenta que el compilador Java 5 genera un código más rápido que el enfoque "StringBuffer" escrito a mano utilizado en versiones anteriores de Java. Si usa "+", esta y futuras mejoras son gratuitas.
fuente
Parece haber cierto debate sobre si aún se necesita usar StringBuilder con los compiladores actuales. Así que pensé en dar mis 2 centavos de experiencia.
Tengo un
JDBC
conjunto de resultados de 10k registros (sí, los necesito todos en un lote). El uso del operador + lleva aproximadamente 5 minutos en mi máquinaJava 1.8
. UsarstringBuilder.append("")
toma menos de un segundo para la misma consulta.Entonces la diferencia es enorme. Dentro de un bucle
StringBuilder
es mucho más rápido.fuente
La concatenación de cadenas sabia de rendimiento usando '+' es más costosa porque tiene que hacer una copia completamente nueva de la cadena ya que las cadenas son inmutables en Java. Esto juega un papel particular si la concatenación es muy frecuente, por ejemplo: dentro de un bucle. Lo siguiente es lo que sugiere mi IDEA cuando intento hacer algo así:
Reglas generales:
Aquí hay un buen blog de Jon Skeet sobre este tema.
fuente
¿Puedo señalar que si va a iterar sobre una colección y utilizar StringBuilder, puede consultar Apache Commons Lang y StringUtils.join () (en diferentes sabores)?
Independientemente del rendimiento, le ahorrará tener que crear StringBuilders y bucles por lo que parece ser la millonésima vez.
fuente
Esto es lo que verifiqué en Java8
Usando StringBuilder
fuente
Creo que deberíamos ir con el enfoque de agregar StringBuilder. Razón de ser :
La cadena concatenada creará un nuevo objeto de cadena cada vez (como la cadena es un objeto inmutable), por lo que creará 3 objetos.
Con el generador de cadenas solo se creará un objeto [StringBuilder es mutable] y la cadena adicional se agregará a él.
fuente
Para cadenas simples como esa prefiero usar
En orden, diría que el método preferido para construir una cadena es usar StringBuilder, String # concat (), luego el operador sobrecargado +. StringBuilder es un aumento significativo del rendimiento cuando se trabaja con cadenas grandes al igual que el uso del operador + es una gran disminución en el rendimiento (disminución exponencialmente grande a medida que aumenta el tamaño de la cadena). El único problema con el uso de .concat () es que puede arrojar NullPointerExceptions.
fuente