La forma "antigua" genera un montón de StringBuilder
operaciones orientadas. Considere este programa:
public class Example {
public static void main(String[] args)
{
String result = args[0] + "-" + args[1] + "-" + args[2];
System.out.println(result);
}
}
Si compilamos eso con JDK 8 o anterior y luego usamos javap -c Example
para ver el código de bytes, vemos algo como esto:
Ejemplo de clase pública {
Ejemplo público ();
Código:
0: aload_0
1: invocarespecial # 1 // Método java / lang / Object. "<init>" :() V
4: regreso
public static void main (java.lang.String []);
Código:
0: nuevo # 2 // clase java / lang / StringBuilder
3: dup
4: invokespecial # 3 // Método java / lang / StringBuilder. "<init>" :() V
7: aload_0
8: iconst_0
9: aaload
10: invokevirtual # 4 // Método java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
13: ldc # 5 // Cadena -
15: invokevirtual # 4 // Método java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
18: aload_0
19: iconst_1
20: aaload
21: invokevirtual # 4 // Método java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
24: ldc # 5 // Cadena -
26: invokevirtual # 4 // Método java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
29: aload_0
30: iconst_2
31: aaload
32: invokevirtual # 4 // Método java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
35: invokevirtual # 6 // Método java / lang / StringBuilder.toString :() Ljava / lang / String;
38: astore_1
39: getstatic # 7 // Campo java / lang / System.out: Ljava / io / PrintStream;
42: aload_1
43: invokevirtual # 8 // Método java / io / PrintStream.println: (Ljava / lang / String;) V
46: regreso
}
Como puede ver, crea StringBuilder
y usa append
. Esto es bastante ineficiente ya que la capacidad predeterminada del búfer incorporado StringBuilder
es de solo 16 caracteres, y el compilador no tiene forma de saber que debe asignar más por adelantado, por lo que termina teniendo que reasignar. También es un montón de llamadas a métodos. (Sin embargo, tenga en cuenta que la JVM a veces puede detectar y reescribir estos patrones de llamadas para hacerlos más eficientes).
Veamos lo que genera Java 9:
Ejemplo de clase pública {
Ejemplo público ();
Código:
0: aload_0
1: invocarespecial # 1 // Método java / lang / Object. "<init>" :() V
4: regreso
public static void main (java.lang.String []);
Código:
0: aload_0
1: iconst_0
2: aaload
3: aload_0
4: iconst_1
5: aaload
6: aload_0
7: iconst_2
8: aaload
9: invokedynamic # 2, 0 // InvokeDynamic # 0: makeConcatWithConstants: (Ljava / lang / String; Ljava / lang / String; Ljava / lang / String;) Ljava / lang / String;
14: astore_1
15: getstatic # 3 // Campo java / lang / System.out: Ljava / io / PrintStream;
18: aload_1
19: invokevirtual # 4 // Método java / io / PrintStream.println: (Ljava / lang / String;) V
22: regreso
}
Oh Dios, pero eso es más corto. :-) Hace una sola llamada a makeConcatWithConstants
from StringConcatFactory
, que dice esto en su Javadoc:
Métodos para facilitar la creación de métodos de concatenación de cadenas, que se pueden utilizar para concatenar eficazmente un número conocido de argumentos de tipos conocidos, posiblemente después de la adaptación de tipos y la evaluación parcial de argumentos. Estos métodos se utilizan normalmente como métodos de arranque para invokedynamic
sitios de llamadas, para admitir la función de concatenación de cadenas del lenguaje de programación Java.