Le "vieux" chemin de sortie d'un tas d' StringBuilder
-opérations orientées. Considérons 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 qu'avec JDK 8 ou une version antérieure, puis utiliser javap -c Example
voir le bytecode, nous voyons quelque chose comme ceci:
public class Exemple {
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: nouvelle #2 // de la classe java/lang/StringBuilder
3: dup
4: invokespecial #3 // Méthode java/lang/StringBuilder."<init>":()V
7: aload_0
8: iconst_0
9: aaload
10: invokevirtual #4 // Méthode java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
13: pma #5 // la 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: pma #5 // la 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 // Domaine java/lang/Système.out:Ljava/io/PrintStream;
42: aload_1
43: invokevirtual #8 // Méthode java/io/PrintStream.println:(Ljava/lang/String;)V
46: le retour
}
Comme vous pouvez le voir, il crée un StringBuilder
et utilisations append
. Ceci est célèbre assez inefficaces comme la valeur par défaut de la capacité de la mémoire tampon intégré en StringBuilder
'est que de 16 caractères, et il n'y a aucun moyen pour le compilateur de savoir à allouer plus à l'avance, de sorte qu'il finit par avoir à réaffecter. C'est aussi un tas d'appels de méthode. (À noter que la JVM peut parfois détecter et de réécrire ces motifs d'appels pour les rendre plus efficaces, cependant).
Regardons ce que Java 9 génère:
public class Exemple {
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: 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 // Domaine java/lang/Système.out:Ljava/io/PrintStream;
18: aload_1
19: invokevirtual #4 // Méthode java/io/PrintStream.println:(Ljava/lang/String;)V
22: le retour
}
Oh mon dieu mais c'est plus court. :-) Il fait un seul appel à l' makeConcatWithConstants
de StringConcatFactory
, qui dit ceci dans sa Javadoc:
Méthodes pour faciliter la création de concaténation de Chaîne méthodes, qui peuvent être utilisés efficacement concaténer un nombre connu des arguments de types connus après, éventuellement, le type de l'adaptation et de l'évaluation partielle des arguments. Ces méthodes sont généralement utilisées comme méthodes bootstrap pour invokedynamic
sites d'appel, à l'appui de la concaténation de chaîne fonction du Langage de Programmation Java.