Je lis " Java meilleur, plus rapide et plus léger " (par Bruce Tate et Justin Gehtland) et je connais les exigences de lisibilité dans les équipes de type agile, comme ce que Robert Martin discute dans ses livres de codage propres. Dans l'équipe où je suis maintenant, on m'a dit explicitement de ne pas utiliser le +
, car il crée des objets chaîne supplémentaires (et inutiles) pendant l'exécution.
Mais cela article , écrit en '04, explique comment l'allocation d'objet est d'environ 10 instructions machine. (essentiellement gratuit)
Il explique également comment le GC contribue également à réduire les coûts dans cet environnement.
Quels sont les compromis de performances réels entre l'utilisation de +
, StringBuilder
ou StringBuffer
? (Dans mon cas, c'est StringBuffer
uniquement car nous sommes limités à Java 1.4.2.)
StringBuffer
pour moi se traduit par un code laid et moins lisible, comme le montrent quelques exemples dans le livre de Tate. Et StringBuffer
est synchronisé avec les threads, ce qui semble avoir ses propres coûts qui l'emportent sur le "danger" de l'utilisation de +
opérateur.
Réflexions/opinions?
L'utilisation de la concaténation String
est traduite en opérations StringBuilder
par le compilateur.
Pour voir comment fonctionne le compilateur, je vais prendre un exemple de classe, le compiler et le décompiler avec jad pour voir quel est le bytecode généré.
Classe d'origine:
public void method1() {
System.out.println("The answer is: " + 42);
}
public void method2(int value) {
System.out.println("The answer is: " + value);
}
public void method3(int value) {
String a = "The answer is: " + value;
System.out.println(a + " what is the question ?");
}
La classe décompilée:
public void method1()
{
System.out.println("The answer is: 42");
}
public void method2(int value)
{
System.out.println((new StringBuilder("The answer is: ")).append(value).toString());
}
public void method3(int value)
{
String a = (new StringBuilder("The answer is: ")).append(value).toString();
System.out.println((new StringBuilder(String.valueOf(a))).append(" what is the question ?").toString());
}
method1
le compilateur a effectué l'opération au moment de la compilation.method2
la concaténation String
équivaut à utiliser manuellement StringBuilder
.method3
la concaténation String
est définitivement mauvaise car le compilateur crée un second StringBuilder
plutôt que de réutiliser le précédent.Donc ma règle simple est que les concaténations sont bonnes à moins que vous n'ayez besoin de concaténer à nouveau le résultat: par exemple dans des boucles ou lorsque vous devez stocker un résultat intermédiaire.
Votre équipe doit en savoir plus sur les raisons d'éviter la concaténation répétée de chaînes .
Il y a certainement fois quand il est logique d'utiliser StringBuffer
- en particulier lorsque vous créez une chaîne dans une boucle, surtout si vous n'êtes pas sûr qu'il y aura peu d'itérations dans la boucle. Notez qu'il ne s'agit pas seulement de créer de nouveaux objets - il s'agit de copier toutes les données de texte que vous avez déjà ajoutées. Gardez également à l'esprit que l'allocation d'objets n'est "essentiellement gratuite" que si vous ne pensez pas à la récupération de place. Oui, s'il y a assez de place dans la génération actuelle, il s'agit essentiellement d'incrémenter un pointeur ... mais:
Toutes ces choses sont raisonnablement bon marché dans la mesure où cela ne vaut "généralement" pas de plier un design loin de l'élégance pour éviter de créer des objets ... mais vous ne devriez pas ' t les considérer comme gratuits .
En revanche, il est inutile d'utiliser StringBuffer
dans les cas où vous n'aurez pas besoin des chaînes intermédiaires. Par exemple:
String x = a + b + c + d;
est au moins aussi efficace que:
StringBuffer buffer = new StringBuffer();
buffer.append(a);
buffer.append(b);
buffer.append(c);
buffer.append(d);
String x = buffer.toString();
Pour les petites concaténations, vous pouvez simplement utiliser String et + dans un souci de lisibilité. La performance ne va pas en souffrir. Mais si vous faites beaucoup d'opérations de concaténation, optez pour StringBuffer.