Mejores prácticas / rendimiento: mezclar StringBuilder.append con String.concat

86

Estoy tratando de entender cuál es la mejor práctica y por qué concatenar cadenas literales y variables para diferentes casos. Por ejemplo, si tengo un código como este

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

¿Es esta la manera de hacerlo? En esta publicación , noté que el +operador en Strings crea una nueva instancia de StringBuilder, concatena los operandos y devuelve una conversión de String, que parece mucho más trabajo que simplemente llamar .append(); así que si eso es cierto, entonces eso está fuera de discusión. ¿Pero de qué String.concat()? ¿Es apropiado usarlo .append()para cada concatenación? ¿O solo para variables, y los literales están bien para agregar .concat()?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

¿Cuáles son las reglas generales de mejores prácticas y rendimiento para abordar estas situaciones? ¿Es correcta mi suposición +y realmente no debería usarse?

Nick Rolando
fuente
Creo que básicamente lo tienes. Las opiniones difieren en cuanto a si String + "realmente no debería usarse". El punto es que entiendes las consecuencias
ControlAltDel

Respuestas:

184

+ operador

String s = s1 + s2

Detrás de escena esto se traduce a:

String s = new StringBuilder(s1).append(s2).toString();

Imagínese cuánto trabajo adicional agrega si tiene s1 + s2aquí:

stringBuilder.append(s1 + s2)

en vez de:

stringBuilder.append(s1).append(s2)

Varias cadenas con +

Vale la pena señalar que:

String s = s1 + s2 + s3 + ... +sN

se traduce a:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

Stringcrea una char[]matriz que puede adaptarse a ambos s1y s2. Copia s1y s2contenido a esta nueva matriz. Realmente requiere menos trabajo que el +operador.

StringBuilder.append()

Mantiene una char[]matriz interna que crece cuando es necesario. No char[]se crea ningún extra si el interno es suficientemente grande.

stringBuilder.append(s1.concat(s2))

también se está desempeñando mal porque s1.concat(s2)crea una char[]matriz adicional y copia s1y s2solo para copiar el contenido de la nueva matriz a interno StringBuilder char[].

Dicho esto, debe usar append()todo el tiempo y agregar cadenas sin procesar (su primer fragmento de código es correcto).

Tomasz Nurkiewicz
fuente
Gracias por su ayuda y la explicación detallada; eso es lo que realmente necesitaba.
Nick Rolando
12
Aunque las versiones más nuevas del compilador optimizan automáticamente el operador + para un constructor de cadenas, no es necesariamente bueno asumir que lo hará, ya que las versiones anteriores no lo hacen. Hay un tema muy importante que se está ignorando en toda esta discusión, que en realidad es uno de los propósitos principales de StringBuilder, que es el grupo de cadenas. El uso de un generador de cadenas mantiene todo como char [] y no crea una cadena intermedia como lo hizo el operador + antes de las optimizaciones del compilador (usado para hacer una concat). El uso de concat crea un objeto String intermedio que se almacena en caché pero no se utiliza.
LINEMAN78
Entonces, si estoy haciendo una declaración única (no declaraciones múltiples a través de un método) concatenación en varias cadenas diferentes. ¿Estaría bien usar +en los objetos String en lugar de crear una StringBuilderconcatenación para esta única vez, ya que básicamente hará lo mismo?
Nick Rolando
1
Y si quiero concatizar solo un carácter, ¿es mejor usar .append ('\ n') en lugar de .append ("\ n")? ¿Como un personaje es un tipo primitivo y una cadena es un objeto?
vrwim
3
Segunda edición de Java eficaz : el uso repetido del operador de concatenación de cadenas para concatenar n cadenas requiere un tiempo cuadrático en n. Entonces, ¿sigue siendo relevante?
gkiko
16

El compilador optimiza la concatenación +.

Entonces

int a = 1;
String s = "Hello " + a;

se transforma en

new StringBuilder().append("Hello ").append(1).toString();

Hay un excelente tema aquí explicar por qué debería utilizar el operador +.

Andy Turner
fuente
3
El compilador en realidad optimizaría eso String s = "Hello World";ya que usa literales.
ColinD
@ColinD: +1. Acabo de modificar mi fragmento.
3

El compilador realiza la optimización automáticamente.

El compilador de Java2 convertirá automáticamente lo siguiente:

String s = s1 + s2; 

a

String s = (new StringBuffer()).append(s1).append(s2).toString();

Tomado directamente del sitio web Java Best Practices on Oracles.

Audaz como el amor
fuente
2

Siempre debes usar append.

concatcrea una nueva cadena para que sea bonita como +creo.

Si concatusa +con 2 String final, la JVM puede realizar una optimización, por lo que es lo mismo que hacer una adición en este caso.

alain.janinm
fuente
1

Si concatena exactamente dos cadenas, use String.concat (crea una nueva cadena creando una nueva matriz de caracteres que se ajusta a ambas cadenas y copia las matrices de caracteres de ambas cadenas en ella).

Si concatena varias (más de dos) cadenas en una línea, use + o StringBuilder.append, no importa, ya que el compilador convierte + en StringBuilder.append. Esto es bueno para múltiples cadenas porque mantiene una matriz de caracteres que crece según sea necesario.

Si concatena varias cadenas en varias líneas, cree un StringBuilder y utilice el método append. Al final, cuando haya terminado de agregar cadenas al StringBuilder, use su .toString () - método para crear una cadena a partir de él. Para la concatenación en varias líneas, esto es más rápido que el segundo método, ya que el segundo método crearía un nuevo StringBuilder en cada línea, agregaría las cadenas y luego devolvería a String, mientras que el tercer método solo usa un StringBuilder para todo.

Dakkaron
fuente
0

El +operador de uso es la mejor práctica, también es simple y legible.

El lenguaje Java proporciona soporte especial para el operador de concatenación de cadenas (+) y para la conversión de otros objetos a cadenas. La concatenación de cadenas se implementa a través de la clase StringBuilder (o StringBuffer) y su método append.

Documento oficial: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

Do Nhu Vy
fuente
0

en el nivel de código de bytes no hay diferencia y no estamos comprometiendo la eficiencia allí. En caso de ejecutar el nivel de código de bytes, debe pasar por el método de sobrecarga del operador no en línea para + llamando a append. luego, en el nivel de lenguaje ensamblador (Java está escrito en C y C produce ensamblajes similares al ensamblaje, habrá una llamada de registro adicional para almacenar + llamada de método en la pila y habrá un empuje adicional. (en realidad, el compilador cruzado podría optimizar + operador llamar, en ese caso no hace ninguna diferencia con la eficiencia).

Es una buena práctica tener una forma de aumentar la legibilidad. :)

Shevon Silva
fuente
0

Personalmente prefiero el formateador de cadenas deStrings.format() una línea, simple y fácil de leer .

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F
T04435
fuente
0

Todas las respuestas son bastante buenas y explicativas. Pero sentí que explorar otras técnicas de concatenación de cadenas también ayudaría como: Guava Joiner, Streams, String.format, etc.

Para obtener detalles completos sobre el rendimiento de cada técnica de concatenación, java-string-concatenation-which-way-is-best .

En resumen, el rendimiento de la concatenación varía con no. de cadenas para concatenar. Por ejemplo, para concatenar de 1 a 10 cadenas, estas técnicas funcionan mejor: StringBuilder, StringBuffer y Plus Operator. Y para concatenar cientos de cadenas: Guava Joiner, la biblioteca stringsUtils de Apache también funciona muy bien.

Consulte el blog anterior. Realmente explica muy bien la eficiencia del rendimiento.

Gracias.

codificadorAJ
fuente