strings metodo example concatenar caracteres cadenas java string concatenation

java - metodo - Concatenación de cadenas: concat() vs operador "+"



metodo concat java (11)

¿Qué tal algunas pruebas simples? Utiliza el siguiente código:

long start = System.currentTimeMillis(); String a = "a"; String b = "b"; for (int i = 0; i < 10000000; i++) { //ten million times String c = a.concat(b); } long end = System.currentTimeMillis(); System.out.println(end - start);

  • La versión "a + b" ejecutada en 2500ms .
  • El a.concat(b) ejecutado en 1200ms .

Probado varias veces. La ejecución de la versión concat() tomó la mitad del tiempo en promedio.

Este resultado me sorprendió porque el método concat() siempre crea una nueva cadena (devuelve una " new String(result) ". Es bien sabido que:

String a = new String("a") // more than 20 times slower than String a = "a"

¿Por qué el compilador no fue capaz de optimizar la creación de cadenas en el código "a + b", sabiendo que siempre resultó en la misma cadena? Se podría evitar la creación de una nueva cadena. Si no crees en la declaración anterior, prueba para ti mismo.

Suponiendo la cadena a y b:

a += b a = a.concat(b)

Bajo el capó, ¿son lo mismo?

Aquí está el concat descompilado como referencia. Me gustaría poder descompilar también al operador + para ver qué hace eso.

public String concat(String s) { int i = s.length(); if (i == 0) { return this; } else { char ac[] = new char[count + i]; getChars(0, count, ac, 0); s.getChars(0, i, ac, count); return new String(0, count + i, ac); } }


Básicamente, hay dos diferencias importantes entre + y el método concat .

  1. Si está utilizando el método concat , solo podrá concatenar cadenas mientras que en el caso del operador + , también puede concatenar la cadena con cualquier tipo de datos.

    Por ejemplo:

    String s = 10 + "Hello";

    En este caso, la salida debe ser 10Hello .

    String s = "I"; String s1 = s.concat("am").concat("good").concat("boy"); System.out.println(s1);

    En el caso anterior tienes que proporcionar dos cadenas obligatorias.

  2. La segunda y principal diferencia entre + y concat es que:

    Caso 1: Supongamos que concatino las mismas cadenas con el operador concat de esta manera

    String s="I"; String s1=s.concat("am").concat("good").concat("boy"); System.out.println(s1);

    En este caso, el número total de objetos creados en el grupo es 7 como este:

    I am good boy Iam Iamgood Iamgoodboy

    Caso 2:

    Ahora voy a concatinar las mismas cadenas a través del operador +

    String s="I"+"am"+"good"+"boy"; System.out.println(s);

    En el caso anterior, el número total de objetos creados es solo 5.

    En realidad, cuando concatinamos las cadenas mediante el operador + , se mantiene una clase StringBuffer para realizar la misma tarea de la siguiente manera:

    StringBuffer sb = new StringBuffer("I"); sb.append("am"); sb.append("good"); sb.append("boy"); System.out.println(sb);

    De esta manera creará sólo cinco objetos.

Entonces, estas son las diferencias básicas entre + y el método concat . Disfrutar :)


Corrí una prueba similar a @marcio pero con el siguiente bucle:

String c = a; for (long i = 0; i < 100000L; i++) { c = c.concat(b); // make sure javac cannot skip the loop // using c += b for the alternative }

Solo por si acaso, también lancé StringBuilder.append() . Cada prueba se ejecutó 10 veces, con 100k repeticiones para cada ejecución. Aquí están los resultados:

  • StringBuilder gana las manos abajo. El resultado de la hora del reloj fue 0 para la mayoría de las carreras, y el más largo tomó 16 ms.
  • a += b toma alrededor de 40000ms (40s) para cada ejecución.
  • concat solo requiere 10000ms (10s) por ejecución.

No he descompilado la clase para ver los aspectos internos o ejecutarlo a través del generador de perfiles todavía, pero sospecho que a += b pasa la mayor parte del tiempo creando nuevos objetos de StringBuilder y luego los convierte de nuevo a String .


Cuando se usa +, la velocidad disminuye a medida que aumenta la longitud de la cuerda, pero cuando se usa concat, la velocidad es más estable, y la mejor opción es usar la clase StringBuilder que tiene una velocidad estable para hacer eso.

Supongo que puedes entender por qué. Pero la mejor manera de crear cadenas largas es utilizar StringBuilder () y append (), ya que cualquiera de las velocidades será inaceptable.


El operador + puede trabajar entre una cadena y un valor de tipo de datos de cadena, carácter, entero, doble o flotante. Simplemente convierte el valor a su representación de cadena antes de la concatenación.

El operador concat solo se puede hacer en y con cuerdas. Comprueba la compatibilidad del tipo de datos y emite un error, si no coinciden.

Excepto esto, el código que proporcionaste hace lo mismo.


La mayoría de las respuestas aquí son de 2008. Parece que las cosas han cambiado con el tiempo. Mis últimos puntos de referencia realizados con JMH muestran que en Java 8 + es aproximadamente dos veces más rápido que concat .

Mi punto de referencia:

@Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS) public class StringConcatenation { @org.openjdk.jmh.annotations.State(Scope.Thread) public static class State2 { public String a = "abc"; public String b = "xyz"; } @org.openjdk.jmh.annotations.State(Scope.Thread) public static class State3 { public String a = "abc"; public String b = "xyz"; public String c = "123"; } @org.openjdk.jmh.annotations.State(Scope.Thread) public static class State4 { public String a = "abc"; public String b = "xyz"; public String c = "123"; public String d = "!@#"; } @Benchmark public void plus_2(State2 state, Blackhole blackhole) { blackhole.consume(state.a+state.b); } @Benchmark public void plus_3(State3 state, Blackhole blackhole) { blackhole.consume(state.a+state.b+state.c); } @Benchmark public void plus_4(State4 state, Blackhole blackhole) { blackhole.consume(state.a+state.b+state.c+state.d); } @Benchmark public void stringbuilder_2(State2 state, Blackhole blackhole) { blackhole.consume(new StringBuilder().append(state.a).append(state.b).toString()); } @Benchmark public void stringbuilder_3(State3 state, Blackhole blackhole) { blackhole.consume(new StringBuilder().append(state.a).append(state.b).append(state.c).toString()); } @Benchmark public void stringbuilder_4(State4 state, Blackhole blackhole) { blackhole.consume(new StringBuilder().append(state.a).append(state.b).append(state.c).append(state.d).toString()); } @Benchmark public void concat_2(State2 state, Blackhole blackhole) { blackhole.consume(state.a.concat(state.b)); } @Benchmark public void concat_3(State3 state, Blackhole blackhole) { blackhole.consume(state.a.concat(state.b.concat(state.c))); } @Benchmark public void concat_4(State4 state, Blackhole blackhole) { blackhole.consume(state.a.concat(state.b.concat(state.c.concat(state.d)))); } }

Resultados:

Benchmark Mode Cnt Score Error Units StringConcatenation.concat_2 thrpt 50 24908871.258 ± 1011269.986 ops/s StringConcatenation.concat_3 thrpt 50 14228193.918 ± 466892.616 ops/s StringConcatenation.concat_4 thrpt 50 9845069.776 ± 350532.591 ops/s StringConcatenation.plus_2 thrpt 50 38999662.292 ± 8107397.316 ops/s StringConcatenation.plus_3 thrpt 50 34985722.222 ± 5442660.250 ops/s StringConcatenation.plus_4 thrpt 50 31910376.337 ± 2861001.162 ops/s StringConcatenation.stringbuilder_2 thrpt 50 40472888.230 ± 9011210.632 ops/s StringConcatenation.stringbuilder_3 thrpt 50 33902151.616 ± 5449026.680 ops/s StringConcatenation.stringbuilder_4 thrpt 50 29220479.267 ± 3435315.681 ops/s


No lo creo.

a.concat(b) se implementa en String y creo que la implementación no cambió mucho desde las primeras máquinas Java. La implementación de la operación + depende de la versión de Java y el compilador. Actualmente + se implementa utilizando StringBuffer para que la operación sea lo más rápida posible. Tal vez en el futuro, esto va a cambiar. En versiones anteriores de java + operación en cadenas era mucho más lenta, ya que producía resultados intermedios.

Supongo que += se implementa usando + y se optimiza de manera similar.


No, no del todo.

En primer lugar, hay una ligera diferencia en la semántica. Si a es null , entonces a.concat(b) lanza una NullPointerException pero a+=b tratará el valor original de a como si fuera null . Además, el método concat() solo acepta valores de String , mientras que el operador + convertirá silenciosamente el argumento en una cadena (usando el método toString() para objetos). Entonces el método concat() es más estricto en lo que acepta.

Para mirar debajo del capó, escriba una clase simple con a += b;

public class Concat { String cat(String a, String b) { a += b; return a; } }

Ahora desmóntelo con javap -c (incluido en Sun JDK). Deberías ver un listado que incluye:

java.lang.String cat(java.lang.String, java.lang.String); Code: 0: new #2; //class java/lang/StringBuilder 3: dup 4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V 7: aload_1 8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 11: aload_2 12: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: invokevirtual #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/ String; 18: astore_1 19: aload_1 20: areturn

Entonces, a += b es el equivalente de

a = new StringBuilder() .append(a) .append(b) .toString();

El método concat debería ser más rápido. Sin embargo, con más cadenas, el método StringBuilder gana, al menos en términos de rendimiento.

El código fuente de String y StringBuilder (y su clase base de paquete privado) está disponible en src.zip del Sun JDK. Puede ver que está creando una matriz de caracteres (cambiando el tamaño según sea necesario) y luego la tira cuando crea la String final. En la práctica, la asignación de memoria es sorprendentemente rápida.

Actualización: como señala Pawel Adamski, el rendimiento ha cambiado en un HotSpot más reciente. javac todavía produce exactamente el mismo código, pero el compilador de bytecode hace trampa. Las pruebas simples fallan por completo porque se desecha todo el código. String.hashCode System.identityHashCode (no String.hashCode ) muestra que el código StringBuffer tiene una ligera ventaja. Sujeto a cambios cuando se lance la próxima actualización, o si usa una JVM diferente. De @lukaseder , una lista de intrínsecos de HotSpot JVM .


Para completar, quise agregar que la definición del operador ''+'' se puede encontrar en el JLS SE8 15.18.1 :

Si solo una expresión de operando es de tipo Cadena, la conversión de cadena (§5.1.11) se realiza en el otro operando para producir una cadena en tiempo de ejecución.

El resultado de la concatenación de cadenas es una referencia a un objeto de cadena que es la concatenación de las dos cadenas de operandos. Los caracteres del operando de la izquierda preceden a los caracteres del operando de la derecha en la cadena recién creada.

El objeto String se creó recientemente (§12.5) a menos que la expresión sea una expresión constante (§15.28).

Sobre la implementación, el JLS dice lo siguiente:

Una implementación puede optar por realizar la conversión y la concatenación en un solo paso para evitar crear y luego descartar un objeto String intermedio. Para aumentar el rendimiento de la concatenación de cadenas repetidas, un compilador de Java puede usar la clase StringBuffer o una técnica similar para reducir el número de objetos de cadena intermedios que se crean mediante la evaluación de una expresión.

Para los tipos primitivos, una implementación también puede optimizar la creación de un objeto de envoltorio al convertir directamente de un tipo primitivo a una cadena.

Así que a juzgar por el ''un compilador de Java puede usar la clase StringBuffer o una técnica similar para reducir'', diferentes compiladores podrían producir un byte-code diferente.


Tom es correcto al describir exactamente lo que hace el operador +. Crea un StringBuilder temporal, agrega las partes y termina con toString() .

Sin embargo, todas las respuestas hasta ahora están ignorando los efectos de las optimizaciones de tiempo de ejecución de HotSpot. Específicamente, estas operaciones temporales se reconocen como un patrón común y se reemplazan con un código de máquina más eficiente en tiempo de ejecución.

@marcio: Has creado un micro-benchmark ; con las JVM modernas, esta no es una forma válida de crear un perfil de código.

La razón por la que la optimización en tiempo de ejecución es importante es que muchas de estas diferencias en el código, incluso la creación de objetos, son completamente diferentes una vez que se pone en marcha HotSpot. La única manera de saberlo con seguridad es perfilando su código in situ .

Finalmente, todos estos métodos son de hecho increíblemente rápidos. Este podría ser un caso de optimización prematura. Si tiene un código que concatena muchas cadenas, la forma de obtener la velocidad máxima probablemente no tenga nada que ver con los operadores que elija y, en su lugar, con el algoritmo que está utilizando.


Niyaz tiene razón, pero también vale la pena señalar que el operador especial + puede convertirse en algo más eficiente con el compilador de Java. Java tiene una clase StringBuilder que representa una cadena mutable no segura para subprocesos. Al realizar un montón de concatenaciones de cadenas, el compilador de Java se convierte silenciosamente

String a = b + c + d;

dentro

String a = new StringBuilder(b).append(c).append(d).toString();

que para cuerdas grandes es significativamente más eficiente. Que yo sepa, esto no sucede cuando usas el método concat.

Sin embargo, el método concat es más eficiente cuando se concatena una cadena vacía en una cadena existente. En este caso, la JVM no necesita crear un nuevo objeto String y simplemente puede devolver el existente. Consulte la documentación de concat para confirmar esto.

Entonces, si está muy preocupado por la eficiencia, debe usar el método concat al concatenar cadenas posiblemente vacías, y usar + de lo contrario. Sin embargo, la diferencia de rendimiento debe ser insignificante y probablemente nunca deba preocuparse por esto.