web-dev-qa-db-fra.com

String, StringBuffer et StringBuilder

Dites-moi s'il vous plaît une situation en temps réel pour comparer String, StringBuffer et StringBuilder?

205
JavaUser

Différence de mutabilité:

String est immuable, si vous essayez de modifier leurs valeurs, un autre objet est créé, alors que StringBuffer et StringBuilder sont mutable so ils peuvent changer leurs valeurs.

Différence de sécurité des fils:

La différence entre StringBuffer et StringBuilder est que StringBuffer est thread-safe. Ainsi, lorsque l'application doit être exécutée uniquement dans un seul thread, il est préférable d'utiliser StringBuilder. StringBuilder est plus efficace que StringBuffer.

Situations:

  • Si votre chaîne ne va pas changer, utilisez une classe String car un objet String est immuable.
  • Si votre chaîne peut changer (exemple: beaucoup de logique et d'opérations dans la construction de la chaîne) et ne sera accessible qu'à partir d'un seul thread, l'utilisation de StringBuilder suffit.
  • Si votre chaîne peut changer et que vous y avez accès à partir de plusieurs threads, utilisez un StringBuffer parce que StringBuffer est synchrone afin que vous ayez la sécurité des threads.
368
bakkal
  • Vous utilisez String lorsqu'une structure immuable est appropriée; L'obtention d'une nouvelle séquence de caractères à partir de String peut entraîner une pénalité de performances inacceptable, que ce soit en temps processeur ou en mémoire (l'obtention de sous-chaînes est efficace en termes de CPU car les données ne sont pas copiées, mais cela signifie qu'une quantité de données potentiellement beaucoup plus importante peut rester allouée).
  • Vous utilisez StringBuilder lorsque vous devez créer une séquence de caractères mutable, généralement pour concaténer plusieurs séquences de caractères.
  • Vous utilisez 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/modifientind la chaîne tampon).

Voir un exemple ici .

46
Artefacto

L'essentiel:

String est une classe immuable, elle ne peut pas être changée. StringBuilder est une classe mutable à laquelle il est possible d'ajouter ou de remplacer des caractères, puis de la convertir en un StringStringBuffer est la version synchronisée d'origine de StringBuilder.

Vous devriez préférer StringBuilder dans tous les cas où vous n’avez qu’un seul thread qui accède à votre objet.

Les détails:

Notez également que StringBuilder/Buffers n'est pas magique, ils utilisent simplement un tableau comme objet de support et ce dernier doit être réaffecté chaque fois qu'il est plein. Assurez-vous de créer vos objets StringBuilder/Buffer assez grands à l'origine, sans avoir à les redimensionner constamment à chaque appel de .append().

Le redimensionnement peut devenir très dégénéré. Il redimensionne fondamentalement le tableau de support à 2 fois sa taille actuelle chaque fois qu'il doit être étendu. Cela peut entraîner de grandes quantités de RAM allouées et non utilisées lorsque _ les classes StringBuilder/Buffer commencent à grossir.

Dans Java String x = "A" + "B"; utilise un StringBuilder dans les coulisses. Donc, dans les cas simples, il n’ya aucun avantage à déclarer le vôtre. Mais si vous construisez des objets String de grande taille, disons de moins de 4 ko, déclarer StringBuilder sb = StringBuilder(4096); est bien plus efficace que la concaténation ou l’utilisation de constructeur par défaut qui ne contient que 16 caractères. Si votre String doit être inférieur à 10k, initialisez-le avec le constructeur à 10k pour être sûr. Mais s'il est initialisé à 10k alors vous écrivez un caractère de plus de 10k, il sera ré-alloué et copié dans un tableau de 20k. Donc initialiser haut vaut mieux que bas.

Dans le cas de redimensionnement automatique, le tableau de fond est redistribué et copié en 32 caractères au 17ème caractère; cela se reproduit au 33e caractère et vous devez ensuite réaffecter 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 réellement d'éviter d'utiliser StringBuilder/Buffer en premier lieu.

Cela 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 le StringBuilder/Buffer un peu plus grand que ce que vous pensez avoir besoin si vous ne savez pas tout de suite quelle sera la taille de la variable String, mais vous pouvez le deviner. Une allocation de mémoire légèrement supérieure à vos besoins sera préférable à de nombreuses réaffectations et copies.

Veillez également à initialiser un StringBuilder/Buffer avec un String car cela n'affectera 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 de 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éaffectation et de copie. Appelez .ensureCapacity() avec la taille souhaitée pour que le résultat obtenu soit String.

Les alternatives:

En guise de remarque, si vous effectuez une construction et une manipulation très lourdes String, il existe une alternative beaucoup plus orientée performance appelée Ropes .

Une autre alternative consiste à créer une implémentation StringList en sous-classant ArrayList<String>, et en ajoutant des compteurs pour suivre le nombre de caractères sur chaque .append() et autres opérations de mutation de la liste, puis remplacer .toString() pour créer un StringBuilder de la taille exacte. Si vous avez besoin de parcourir la liste et de créer la sortie, vous pouvez même transformer StringBuilder en une variable d'instance et "mettre en cache" les résultats de .toString(). Vous ne devez donc les générer à nouveau que lorsque quelque chose change.

N'oubliez pas non plus la fonction String.format() lors de la création d'une sortie au format fixe, qui peut être optimisée par le compilateur au fur et à mesure de son amélioration.

28
user177800

Voulez-vous dire, pour la concaténation?

Exemple concret: Vous souhaitez créer une nouvelle chaîne parmi tant d'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 identique à celle de StringBuilder, les effets sont différents)

À propos

StringBuffer vs. 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 s'exécutera beaucoup plus rapidement car il n'arrêtera pas voir si elle possède le verrou de fil.

Donc, il est recommandé d'utiliser StringBuilder (à moins bien sûr que plusieurs threads y aient accès en même temps, ce qui est rare)

La concaténation String ( à l'aide de l'opérateur + ) peut être optimisée par le compilateur pour utiliser StringBuilder en dessous, donc pas plus longtemps Une chose à craindre, dans les temps anciens de Java, c’était quelque chose que tout le monde disait qu'il fallait éviter à tout prix, car chaque concaténation créait un nouvel objet String. Les compilateurs modernes ne le font plus, mais il est néanmoins recommandé d'utiliser StringBuilder au cas où vous utiliseriez un "ancien" compilateur.

modifier

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 sont pour la chaîne nommée "littéral"

Les lignes numérotées 31-53 sont pour la chaîne nommée "constructeur"

Il n'y a pas de différence, c'est exactement le même code qui est exécuté pour les deux chaînes.

9
OscarRyz

String Family

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 _"abc"_, sont implémentés en tant qu'instances de cette classe.

Les objets String sont immutable une fois qu'ils sont créés, nous ne pouvons pas les modifier. ( Les chaînes sont des constantes )

  • Si une chaîne est créée à l'aide d'un constructeur ou d'une méthode, ces chaînes seront stockées dans Heap Memory ainsi que SringConstantPool . Mais avant d'enregistrer dans le pool, il appelle la méthode intern() pour vérifier la disponibilité des objets avec le même contenu dans le pool à l'aide de la méthode equals. Si String-copy est disponible dans le pool, la référence est renvoyée. Dans le cas contraire, l'objet String est ajouté au pool et renvoie la référence.

    • Le langage Java fournit un support spécial pour l'opérateur de concaténation de chaînes (_+_) et pour la conversion d'autres objets en chaînes. La concaténation de chaînes est implémentée via StringBuilder (ou StringBuffer ) class 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 mutables de caractères. 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 de sorte qu'elle soit thread-safe.

  • Les données StringBuffer et StringBuilder peuvent uniquement être créées à l'aide d'un nouvel opérateur. Donc, ils sont stockés dans la mémoire Heap.

  • Les instances de StringBuilder ne peuvent pas être utilisées par plusieurs threads. Si une telle synchronisation est nécessaire, 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 telles que., replace(int start, int end, String str) et reverse().

    NOTE: StringBuffer et SringBuilder sont modifiables 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_. Si vous souhaitez trier Comparable<T> ou comparer une valeur, faites-le dans le cadre des génériques puis 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, utilisez StringBuilder, qui est plus rapide que StringBuffer. Si plusieurs threads modifient la valeur, optez pour StringBuffer.

8
Yash
 --------------------------------------------- ------------------------------------- 
 String StringBuffer StringBuilder 
 -------------------------------------------------- -------------------------------- 
 Zone de stockage | Tas de tas de pool de chaînes constantes 
 Modifiable | Non (immuable) Oui (mutable) Oui (mutable) 
 Thread Safe | Oui Oui Non 
 Performance | Rapide Très lent Rapide 
 --------------------------------------------- ----------------------------------------- 
7
Abhijit Maity

De plus, StringBuffer est thread-safe, ce que StringBuilder ne l'est pas.

Donc, dans une situation en temps réel où différents threads y accèdent, StringBuilder pourrait avoir un résultat indéterministe.

4
Lars Andren

Notez que si vous utilisez Java 5 ou une version plus récente, vous devez utiliser StringBuilder au lieu de StringBuffer. De la documentation de l'API:

À partir de la version JDK 5, cette classe a été complétée par une classe équivalente conçue pour être utilisée par un seul thread, StringBuilder. La classe StringBuilder devrait généralement être utilisée de préférence à celle-ci, car elle supporte toutes les mêmes opérations, mais elle est plus rapide car elle n'effectue aucune synchronisation.

En pratique, vous n'utiliserez presque jamais cela à partir de plusieurs threads en même temps. Par conséquent, la synchronisation effectuée par StringBuffer est presque toujours inutile.

3
Jesper

Personnellement, je ne pense pas qu'il y ait d'utilisation réelle dans le monde pour StringBuffer. Quand pourrais-je vouloir communiquer entre plusieurs threads en manipulant une séquence de caractères? Cela ne semble pas du tout utile, mais peut-être que je n'ai pas encore vu la lumière :)

3
fredoverflow

La différence entre String et les deux autres classes est que String est immuable et que les deux autres sont des classes mutables.

Mais pourquoi avons-nous deux classes dans le même but?

La raison en est que StringBuffer est thread-safe et StringBuilder ne l'est pas. StringBuilder est une nouvelle classe sur StringBuffer Api qui a été introduite dans JDK5 et qui est toujours recommandée si vous travaillez dans un environnement à thread unique car il s'agit de beaucoup Faster

Pour des détails complets, vous pouvez lire http://www.codingeek.com/Java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-Java/

3
Hitesh Garg

En Java, String est immuable. Étant immuable, nous voulons dire qu'une fois qu'une chaîne est créée, nous ne pouvons pas en changer la 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 comparées à d'autres chaînes, le constructeur de chaînes de caractères est plus rapide. Vous pouvez apprendre la différence entre String, StringBuilder et StringBuffer en les implémentant.

2
rajat ghai