Autre question: pourquoi n'utilisez-vous un SB que pour une seule itération de la boucle? Y a-t-il une autre itération intérieure? SB ne vaut pas la peine si vous voulez simplement faire A + B + C + D (le compilateur Java utilisera un SB en interne). Cela aide si vous voulez ajouter conditionnellement des parties de chaînes, mais sinon ... utilisez simplement "+".
helios
Réponses:
135
Une option consiste à utiliser la méthode de suppression comme suit:
StringBuffer sb =newStringBuffer();for(int n =0; n <10; n++){
sb.append("a");// This will clear the buffer
sb.delete(0, sb.length());}
Une autre option (nettoyeur de bits) utilise setLength (int len) :
Quelque chose d'un peu moins stupide serait de simplement déclarer le StringBuffer dans la boucle.
Mark Elliot
11
Ah, je pense que sb.setLength (0); est plus propre et plus efficace que de le déclarer à l'intérieur de la boucle. Votre solution va à l'encontre de l'avantage de performance de l'utilisation de StringBuffer ...
Jon
6
Je pense que l'avantage en termes de performances vient de la mutabilité de la chaîne, pas de la sauvegarde de l'instanciation. voici un test rapide des itérations 1e8: boucle intérieure (2,97s): ideone.com/uyyTL14w , boucle extérieure (2,87s): ideone.com/F9lgsIxh
Mark Elliot
6
En parlant de performances: à moins que votre code ne soit accessible dans un scénario multithread, vous devriez utiliser StringBuilder plutôt que StringBuffer - voir javadoc: "Dans la mesure du possible, il est recommandé d'utiliser cette classe de préférence à StringBuffer car elle sera plus rapide sous la plupart des implémentations ".
Rahel Lüthy
4
Le seul avantage de créer le SB à l'extérieur est de ne pas perdre le caractère interne (potentiellement long) [] de celui-ci. Si dans le premier itérateur il a suffisamment grandi, la deuxième boucle n'aura pas besoin de redimensionner un char []. Mais pour obtenir l'avantage, la "méthode claire" devra conserver la taille du tableau interne. setLength fait cela mais il met également à \ u0000 tous les caractères non utilisés dans le SB, donc il est moins performant que de simplement créer un nouveau SB avec une bonne capacité initiale. Il est préférable de déclarer à l'intérieur de la boucle.
helios
48
Le moyen le plus simple de réutiliser le StringBufferest d'utiliser la méthodesetLength()
sb.setLength(0);// It will just discard the previous data, which will be garbage collected later.
Ou utiliser:
sb.delete(0, sb.length());// A bit slower as it is used to delete sub sequence.
REMARQUE
Évitez de déclarer StringBufferou des StringBuilderobjets dans la boucle sinon cela créera de nouveaux objets à chaque itération. La création d'objets nécessite des ressources système, de l'espace et prend également du temps. Donc pour le long terme, évitez de les déclarer dans une boucle si possible.
Je suggère de créer un nouveau StringBuffer(ou même mieux StringBuilder) pour chaque itération. La différence de performances est vraiment négligeable, mais votre code sera plus court et plus simple.
Si vous avez des preuves d'une telle différence de performance, veuillez les partager. (Je serai également heureux de voir des statistiques sur les endroits où Java est le plus utilisé et sous quelle définition de "principalement".)
Eli Acherkan
1
Il est bien connu que l'allocation (nouveau mot-clé en Java) coûte plus cher que de simplement changer certains champs du même objet. Pour «la plupart du temps», avec lequel vous pourriez répliquer fortement, il y a plus de 1,5 milliard d'appareils Android, tous utilisant Java.
Louis CAD du
1
Je suis d'accord que dans certains cas, la lisibilité du code est plus importante que les performances, mais dans ce cas, ce n'est qu'une ligne de code! Et vous pouvez exécuter un benchmark qui vous prouvera que l'allocation et la création d'objets, ainsi que le ramasse-miettes sont plus chers que de ne pas le faire du tout. Comme nous sommes dans une boucle, c'est plus que pertinent.
Louis CAD du
1
J'ai également souscrit au point de vue de Knuth, mais son point de vue n'est pas toujours vrai. Ajouter une seule ligne pour potentiellement gagner des cycles CPU et de la mémoire n'est absolument pas un mal. Vous prenez l'idée trop juste. Notez qu'une boucle est généralement répétée plusieurs fois. Une boucle peut être répétée des milliers de fois, ce qui peut consommer de précieux mégaoctets sur un mobile (et également sur un serveur ou un ordinateur) si elle n'est pas optimisée avec soin.
Louis CAD
1
Je pense que nous avons tous les deux énoncé nos points de vue assez clairement, et je pense qu'une discussion plus approfondie ne sera pas bénéfique pour cette section de commentaires. Si vous pensez que ma réponse est incorrecte, trompeuse ou incomplète, alors vous - ou n'importe qui - êtes bienvenu pour la modifier et / ou la voter contre.
Déjà bonne réponse là-bas. Ajoutez simplement un résultat de référence pour la différence de performance StringBuffer et StringBuild, utilisez une nouvelle instance en boucle ou utilisez setLength (0) en boucle.
Le résumé est: Dans une grande boucle
StringBuilder est beaucoup plus rapide que StringBuffer
Créer une nouvelle instance StringBuilder en boucle n'a aucune différence avec setLength (0). (setLength (0) a un très très très petit avantage que de créer une nouvelle instance.)
StringBuffer est plus lent que StringBuilder en créant une nouvelle instance en boucle
setLength (0) de StringBuffer est extrêmement plus lent que la création d'une nouvelle instance en boucle.
Benchmark très simple (je viens de changer manuellement le code et de faire un test différent):
publicclassStringBuilderSpeed{publicstaticfinalchar ch[]=newchar[]{'a','b','c','d','e','f','g','h','i'};publicstaticvoid main(String a[]){int loopTime =99999999;long startTime =System.currentTimeMillis();StringBuilder sb =newStringBuilder();for(int i =0; i < loopTime; i++){for(char c : ch){
sb.append(c);}
sb.setLength(0);}long endTime =System.currentTimeMillis();System.out.println("Time cost: "+(endTime - startTime));}
}
Nouvelle instance StringBuilder en boucle: coût en temps: 3693, 3862, 3624, 3742
StringBuilder setLength: Coût du temps: 3465, 3421, 3557, 3408
Nouvelle instance StringBuffer en boucle: coût en temps: 8327, 8324, 8284
StringBuffer setLength Coût du temps: 22878, 23017, 22894
Encore une fois StringBuilder setLength pour m'assurer que mon laboratoire n'a pas de problème à utiliser si longtemps pour StringBuffer setLength :-) Coût du temps: 3448
Réponses:
Une option consiste à utiliser la méthode de suppression comme suit:
Une autre option (nettoyeur de bits) utilise setLength (int len) :
Voir Javadoc pour plus d'informations:
la source
Le moyen le plus simple de réutiliser le
StringBuffer
est d'utiliser la méthodesetLength()
public void setLength(int newLength)
Vous pouvez avoir le cas comme
la source
setLength
place desetlength
.Vous avez deux options:
Soit utiliser:
Ou utiliser:
REMARQUE
Évitez de déclarer
StringBuffer
ou desStringBuilder
objets dans la boucle sinon cela créera de nouveaux objets à chaque itération. La création d'objets nécessite des ressources système, de l'espace et prend également du temps. Donc pour le long terme, évitez de les déclarer dans une boucle si possible.la source
la source
Je suggère de créer un nouveau
StringBuffer
(ou même mieuxStringBuilder
) pour chaque itération. La différence de performances est vraiment négligeable, mais votre code sera plus court et plus simple.la source
Usage:
pour la lisibilité, je pense que c'est la meilleure solution.
la source
Déjà bonne réponse là-bas. Ajoutez simplement un résultat de référence pour la différence de performance StringBuffer et StringBuild, utilisez une nouvelle instance en boucle ou utilisez setLength (0) en boucle.
Le résumé est: Dans une grande boucle
Benchmark très simple (je viens de changer manuellement le code et de faire un test différent):
}
Nouvelle instance StringBuilder en boucle: coût en temps: 3693, 3862, 3624, 3742
StringBuilder setLength: Coût du temps: 3465, 3421, 3557, 3408
Nouvelle instance StringBuffer en boucle: coût en temps: 8327, 8324, 8284
StringBuffer setLength Coût du temps: 22878, 23017, 22894
Encore une fois StringBuilder setLength pour m'assurer que mon laboratoire n'a pas de problème à utiliser si longtemps pour StringBuffer setLength :-) Coût du temps: 3448
la source
je pense que ce code est plus rapide.
la source