Réponses:
Différence de mutabilité:
String
est immuable , si vous essayez de modifier leurs valeurs, un autre objet est créé, tandis que StringBuffer
et StringBuilder
sont mutables afin qu'elles puissent changer leurs valeurs.
Différence de sécurité de fil:
La différence entre StringBuffer
et StringBuilder
est que StringBuffer
c'est thread-safe. Ainsi, lorsque l'application doit être exécutée uniquement dans un seul thread, il est préférable de l'utiliser StringBuilder
. StringBuilder
est plus efficace que StringBuffer
.
Situations:
String
objet est immuable.StringBuilder
est suffisant.StringBuffer
car StringBuffer
est synchrone afin que vous ayez la sécurité des threads.Strings
lorsque nous modifions la valeur, un autre objet est créé. L'ancienne référence d'objet est-elle annulée afin qu'elle puisse être récupérée par le GC
ou est-elle même récupérée?
String
avec StringBuilder
?
String
lorsqu'une structure immuable est appropriée; l'obtention d'une nouvelle séquence de caractères à partir d'un String
peut entraîner une pénalité de performance inacceptable, que ce soit en temps CPU ou en mémoire (l'obtention de sous-chaînes est efficace CPU car les données ne sont pas copiées, mais cela signifie qu'une quantité potentiellement beaucoup plus importante de données peut rester allouée).StringBuilder
lorsque vous devez créer une séquence de caractères modifiable, généralement pour concaténer plusieurs séquences de caractères ensemble.StringBuffer
dans les mêmes circonstances que vous utiliseriez StringBuilder
, mais lorsque les modifications apportées à la chaîne sous-jacente doivent être synchronisées (car plusieurs threads lisent / modifient le tampon de chaîne).Voir un exemple ici .
Les bases:
String
est une classe immuable, elle ne peut pas être modifiée.
StringBuilder
est une classe modifiable qui peut être ajoutée, les caractères remplacés ou supprimés et finalement convertis en String
StringBuffer
est la version synchronisée d'origine deStringBuilder
Vous devriez préférer StringBuilder
dans tous les cas où vous n'avez qu'un seul thread accéder à votre objet.
Les détails:
Notez également que ce StringBuilder/Buffers
n'est pas magique, ils utilisent simplement un tableau comme objet de support et que le tableau doit être réalloué chaque fois qu'il est plein. Soyez sûr et créez vos StringBuilder/Buffer
objets assez grands à l'origine où ils n'ont pas besoin d'être constamment redimensionnés à chaque .append()
appel.
Le redimensionnement peut devenir très dégénéré. Il redimensionne fondamentalement le tableau de sauvegarde à 2 fois sa taille actuelle chaque fois qu'il doit être étendu. Cela peut entraîner l'allocation de grandes quantités de RAM et leur non-utilisation lorsque les StringBuilder/Buffer
classes commencent à grossir.
En Java String x = "A" + "B";
utilise un StringBuilder
dans les coulisses. Donc, pour les cas simples, il n'y a aucun avantage à déclarer le vôtre. Mais si vous construisez des String
objets qui sont grands, disons moins de 4k, alors déclarer StringBuilder sb = StringBuilder(4096);
est beaucoup plus efficace que la concaténation ou utiliser le constructeur par défaut qui n'est que de 16 caractères. Si votre String
va être inférieur à 10k, initialisez-le avec le constructeur à 10k pour être sûr. Mais s'il est initialisé à 10k alors vous écrivez 1 caractère de plus que 10k, il sera réalloué et copié dans un tableau de 20k. Il est donc préférable d'initialiser haut que bas.
Dans le cas du redimensionnement automatique, au 17e caractère, le tableau de sauvegarde est réalloué et copié sur 32 caractères, au 33e caractère, cela se produit à nouveau et vous pouvez réallouer et copier le tableau en 64 caractères. Vous pouvez voir comment cela dégénère en beaucoup de réallocations et de copies, ce que vous essayez vraiment d'éviter d'utiliser StringBuilder/Buffer
en premier lieu.
Ceci provient du code source JDK 6 pour AbstractStringBuilder
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
Une meilleure pratique consiste à initialiser StringBuilder/Buffer
un peu plus grand que vous pensez que vous aurez besoin si vous ne savez pas tout de suite quelle String
sera la taille mais vous pouvez le deviner. Une allocation de mémoire légèrement supérieure à celle dont vous avez besoin sera meilleure que de nombreuses réallocations et copies.
Méfiez-vous également d'initialiser un StringBuilder/Buffer
avec un String
car cela n'allouera que la taille de la chaîne + 16 caractères, ce qui dans la plupart des cas ne fera que démarrer le cycle de réallocation et de copie dégénéré que vous essayez d'éviter. Ce qui suit est directement issu du code source Java 6.
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
Si, par hasard, vous vous retrouvez avec une instance StringBuilder/Buffer
que vous n'avez pas créée et que vous ne pouvez pas contrôler le constructeur appelé, il existe un moyen d'éviter le comportement dégénéré de réallocation et de copie. Appelez .ensureCapacity()
avec la taille que vous souhaitez pour vous assurer que votre résultat String
s'intégrera.
Les alternatives:
Tout comme une note, si vous faites de la String
construction et de la manipulation très lourdes , il existe une alternative beaucoup plus axée sur les performances appelée Cordes .
Une autre alternative consiste à créer une StringList
implémentation en sous-classant ArrayList<String>
et en ajoutant des compteurs pour suivre le nombre de caractères sur chaque .append()
opération de mutation de la liste, puis remplacer .toString()
pour créer une StringBuilder
taille exacte dont vous avez besoin et parcourir la liste et construire la sortie, vous pouvez même en faire StringBuilder
une variable d'instance et «mettre en cache» les résultats .toString()
et ne devez la régénérer que lorsque quelque chose change.
N'oubliez pas non plus de String.format()
créer une sortie au format fixe, qui peut être optimisée par le compilateur au fur et à mesure qu'elle l'améliore.
String x = "A" + "B";
vraiment pour être un StringBuilder? Pourquoi ne compilerait-il pas simplement String x = "AB";
, il ne devrait utiliser un StringBuilder que si les composants ne sont pas connus au moment de la compilation.
Voulez-vous dire, pour la concaténation?
Exemple réel: vous souhaitez créer une nouvelle chaîne à partir de nombreuses autres .
Par exemple pour envoyer un message:
Chaîne
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
Ou
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer (la syntaxe est exactement comme avec StringBuilder, les effets diffèrent)
À propos
StringBuffer
contre. StringBuilder
Le premier est synchronisé et plus tard ne l'est pas.
Donc, si vous l'invoquez plusieurs fois dans un seul thread (ce qui représente 90% des cas), StringBuilder
il s'exécutera beaucoup plus rapidement car il ne s'arrêtera pas pour voir s'il possède le verrou de thread.
Donc, il est recommandé de l'utiliser StringBuilder
(à moins bien sûr que vous ayez plus d'un thread y accédant en même temps, ce qui est rare)
String
la concaténation (en utilisant l'opérateur + ) peut être optimisée par le compilateur pour l'utiliser en StringBuilder
dessous, donc, ce n'est plus quelque chose à craindre, dans les jours les plus anciens de Java, c'était quelque chose que tout le monde devrait éviter à tout prix, car chaque concaténation créé un nouvel objet String. Les compilateurs modernes ne le font plus, mais c'est toujours une bonne pratique à utiliser à la StringBuilder
place au cas où vous utilisez un "ancien" compilateur.
Éditer
Juste pour qui est curieux, voici ce que le compilateur fait pour cette classe:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
Les lignes numérotées de 5 à 27 correspondent à la chaîne nommée "littéral"
Les lignes numérotées 31-53 correspondent à la chaîne nommée "builder"
Il n'y a aucune différence, exactement le même code est exécuté pour les deux chaînes.
StringBuilder
concaténation de chaîne à faire sur le côté droit de l'affectation. Toute bonne implémentation utilisera un StringBuilder dans les coulisses comme vous le dites. De plus, votre exemple "a" + "b"
serait compilé en un seul littéral, "ab"
mais si vous l'utilisiez, StringBuilder
il en résulterait deux appels inutiles à append()
.
"a"+"b"
mais pour dire ce qu'était une concaténation de chaînes, je la change pour être explicite. Ce que vous ne dites pas, c'est pourquoi ce n'est pas une bonne pratique de le faire. C'est exactement ce que fait un compilateur (moderne). @ flou, je suis d'accord, surtout quand vous savez quelle serait la taille de la chaîne finale (aprox).
-------------------------------------------------- -------------------------------- String StringBuffer StringBuilder -------------------------------------------------- -------------------------------- Zone de stockage | Tas de chaînes de pool de chaînes constantes Modifiable | Non (immuable) Oui (mutable) Oui (mutable) Thread Safe | Oui oui non Performance | Rapide Très lent Rapide -------------------------------------------------- --------------------------------
synchronised
et c'est pourquoi .
Chaîne
Le String class
représente des chaînes de caractères. Tous les littéraux de chaîne du programme Java, tels que ceux qui "abc"
sont implémentés en tant qu'instances de cette classe.
Les objets chaîne sont immuables une fois qu'ils sont créés, nous ne pouvons pas changer. (Les chaînes sont des constantes )
Si une chaîne est créée en utilisant constructeur ou méthode alors ces chaînes seront stockées dans Heap mémoire ainsi que SringConstantPool
. Mais avant d'enregistrer dans le pool, il invoque une intern()
méthode pour vérifier la disponibilité des objets avec le même contenu dans le pool en utilisant la méthode equals. Si la copie de chaîne est disponible dans le pool, renvoie la référence. Sinon, l'objet String est ajouté au pool et renvoie la référence.
+
) et pour la conversion d'autres objets en chaînes. La concaténation de chaînes est implémentée via la classe StringBuilder (ou StringBuffer) et sa méthode append.String heapSCP = new String("Yash");
heapSCP.concat(".");
heapSCP = heapSCP + "M";
heapSCP = heapSCP + 777;
// For Example: String Source Code
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
Les littéraux de chaîne sont stockés dans StringConstantPool
.
String onlyPool = "Yash";
StringBuilder et StringBuffer sont des séquences de caractères modifiables. Cela signifie que l'on peut changer la valeur de ces objets. StringBuffer a les mêmes méthodes que StringBuilder, mais chaque méthode de StringBuffer est synchronisée, elle est donc thread-safe.
Les données StringBuffer et StringBuilder ne peuvent être créées qu'en utilisant un nouvel opérateur. Ainsi, ils sont stockés dans la mémoire du tas.
Les instances de StringBuilder ne sont pas sûres pour une utilisation par plusieurs threads. Si une telle synchronisation est requise, il est recommandé d'utiliser StringBuffer.
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer et StringBuilder ont des méthodes spéciales comme.,
replace(int start, int end, String str)
Et reverse()
.
REMARQUE : StringBuffer et SringBuilder sont mutables car ils fournissent l'implémentation de
Appendable Interface
.
Quand utiliser lequel?
Si vous n'allez pas changer la valeur à chaque fois, il vaut mieux utiliser String Class
. Dans le cadre de Generics si vous souhaitez trier Comparable<T>
ou comparer une valeur, optez pour String Class
.
//ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add( threadSafe );
System.out.println("Set : "+ set);
Si vous allez modifier la valeur à chaque fois, optez pour StringBuilder qui est plus rapide que StringBuffer. Si plusieurs threads modifient la valeur, optez pour StringBuffer.
En outre, StringBuffer
est thread-safe, ce qui StringBuilder
n'est pas le cas.
Ainsi, dans une situation en temps réel lorsque différents threads y accèdent, cela StringBuilder
pourrait avoir un résultat non déterministe.
Notez que si vous utilisez Java 5 ou une version plus récente, vous devez utiliser à la StringBuilder
place de StringBuffer
. Dans la documentation de l'API:
Avec la version 5 JDK, cette classe a été complétée par une classe équivalente conçue pour être utilisée par un seul fil,
StringBuilder
. LaStringBuilder
classe doit généralement être utilisée de préférence à celle-ci, car elle prend en charge toutes les mêmes opérations mais elle est plus rapide, car elle n'effectue aucune synchronisation.
Dans la pratique, vous n'utiliserez presque jamais cela à partir de plusieurs threads en même temps, donc la synchronisation qui le StringBuffer
fait est presque toujours inutile.
Personnellement, je ne pense pas que le monde réel puisse être utilisé StringBuffer
. Quand voudrais-je jamais communiquer entre plusieurs threads en manipulant une séquence de caractères? Cela ne semble pas du tout utile, mais je n'ai peut-être pas encore vu la lumière :)
La différence entre String et les deux autres classes est que String est immuable et les deux autres sont des classes mutables.
Mais pourquoi nous avons deux classes dans le même but?
La raison en est que StringBuffer
Thread est sûr et StringBuilder
ne l'est pas.
StringBuilder
est une nouvelle classe StringBuffer Api
et elle a été introduite dans JDK5
et est toujours recommandée si vous travaillez dans un environnement à thread unique car c'est beaucoupFaster
Pour des détails complets, vous pouvez lire http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
En java, String est immuable. Étant immuables, nous voulons dire qu'une fois qu'une chaîne est créée, nous ne pouvons pas changer sa valeur. StringBuffer est modifiable. Une fois qu'un objet StringBuffer est créé, nous ajoutons simplement le contenu à la valeur de l'objet au lieu de créer un nouvel objet. StringBuilder est similaire à StringBuffer mais il n'est pas thread-safe. Les méthodes de StingBuilder ne sont pas synchronisées mais par rapport aux autres chaînes, le Stringbuilder s'exécute le plus rapidement. Vous pouvez apprendre la différence entre String, StringBuilder et StringBuffer en les implémentant.