L '«ancienne» méthode produit un tas d' StringBuilder
opérations orientées. Considérez ce programme:
public class Example {
public static void main(String[] args)
{
String result = args[0] + "-" + args[1] + "-" + args[2];
System.out.println(result);
}
}
Si nous compilons cela avec JDK 8 ou une version antérieure et que nous utilisons ensuite javap -c Example
pour voir le bytecode, nous voyons quelque chose comme ceci:
Exemple de classe publique {
Exemple public ();
Code:
0: aload_0
1: invokespecial # 1 // Méthode java / lang / Object. "<init>" :() V
4: retour
public static void main (java.lang.String []);
Code:
0: nouveau # 2 // classe java / lang / StringBuilder
3: dup
4: invokespecial # 3 // Méthode java / lang / StringBuilder. "<init>" :() V
7: aload_0
8: iconst_0
9: une charge
10: invokevirtual # 4 // Méthode java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
13: ldc # 5 // Chaîne -
15: invokevirtual # 4 // Méthode java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
18: aload_0
19: iconst_1
20: aaload
21: invokevirtual # 4 // Méthode java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
24: ldc # 5 // Chaîne -
26: invokevirtual # 4 // Méthode java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
29: aload_0
30: iconst_2
31: aaload
32: invokevirtual # 4 // Méthode java / lang / StringBuilder.append: (Ljava / lang / String;) Ljava / lang / StringBuilder;
35: invokevirtual # 6 // Méthode java / lang / StringBuilder.toString :() Ljava / lang / String;
38: astore_1
39: getstatic # 7 // Champ java / lang / System.out: Ljava / io / PrintStream;
42: aload_1
43: invokevirtual # 8 // Méthode java / io / PrintStream.println: (Ljava / lang / String;) V
46: retour
}
Comme vous pouvez le voir, il crée un StringBuilder
et utilise append
. Ceci est réputé assez inefficace car la capacité par défaut du tampon intégré StringBuilder
n'est que de 16 caractères, et il n'y a aucun moyen pour le compilateur de savoir d'allouer plus à l'avance, donc il finit par devoir réallouer. C'est aussi un tas d'appels de méthode. (Notez que la JVM peut parfois détecter et réécrire ces modèles d'appels pour les rendre plus efficaces, cependant.)
Regardons ce que génère Java 9:
Exemple de classe publique {
Exemple public ();
Code:
0: aload_0
1: invokespecial # 1 // Méthode java / lang / Object. "<init>" :() V
4: retour
public static void main (java.lang.String []);
Code:
0: aload_0
1: iconst_0
2: une charge
3: aload_0
4: iconst_1
5: une charge
6: aload_0
7: iconst_2
8: une charge
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 // Champ java / lang / System.out: Ljava / io / PrintStream;
18: aload_1
19: invokevirtual # 4 // Méthode java / io / PrintStream.println: (Ljava / lang / String;) V
22: retour
}
Oh mon mais c'est plus court. :-) Il fait un seul appel à makeConcatWithConstants
from StringConcatFactory
, qui dit ceci dans son Javadoc:
Méthodes pour faciliter la création de méthodes de concaténation String, qui peuvent être utilisées pour concaténer efficacement un nombre connu d'arguments de types connus, éventuellement après adaptation de type et évaluation partielle des arguments. Ces méthodes sont généralement utilisées comme méthodes d'amorçage pour invokedynamic
les sites d'appel, pour prendre en charge la fonction de concaténation de chaînes du langage de programmation Java.