String, StringBuffer e StringBuilder

Per favore dimmi una situazione in tempo reale per confrontare String , StringBuffer e StringBuilder ?

Differenza di mutabilità:

String è immutabile , se provi a modificare i loro valori, viene creato un altro object, mentre StringBuffer e StringBuilder sono modificabili in modo che possano cambiare i loro valori.

Differenza di sicurezza del filo:

La differenza tra StringBuffer e StringBuilder è che StringBuffer è thread-safe. Quindi, quando l’applicazione deve essere eseguita solo in un singolo thread, è meglio usare StringBuilder . StringBuilder è più efficiente di StringBuffer .

situazioni:

  • Se la tua stringa non cambierà, usa una class String perché un object String è immutabile.
  • Se la tua stringa può cambiare (esempio: molte logiche e operazioni nella costruzione della stringa) e sarà accessibile solo da un singolo thread, l’uso di un StringBuilder è abbastanza buono.
  • Se la stringa può essere modificata e sarà accessibile da più thread, utilizzare un object StringBuffer perché StringBuffer è sincrono in modo da garantire la sicurezza del thread.
  • Tu usi String quando una struttura immutabile è appropriata; ottenere una nuova sequenza di caratteri da una String può comportare una penalizzazione delle prestazioni inaccettabile, sia nel tempo della CPU che nella memoria (ottenere sottostringhe è efficiente per la CPU perché i dati non vengono copiati, ma ciò significa che una quantità potenzialmente maggiore di dati può rimanere allocata).
  • Si utilizza StringBuilder quando è necessario creare una sequenza di caratteri mutabili, in genere per concatenare più sequenze di caratteri insieme.
  • StringBuffer nelle stesse circostanze in cui StringBuilder , ma quando le modifiche alla stringa sottostante devono essere sincronizzate (poiché molti thread stanno leggendo / modificano il buffer delle stringhe).

Guarda un esempio qui .

Le basi:

String è una class immutabile, non può essere modificata. StringBuilder è una class mutabile che può essere aggiunta, caratteri sostituiti o rimossi e infine convertita in String StringBuffer è la versione sincronizzata originale di StringBuilder

Dovresti preferire StringBuilder in tutti i casi in cui hai solo un singolo thread che accede al tuo object.

I dettagli:

Si noti inoltre che StringBuilder/Buffers non sono magici, usano solo una matrice come object di supporto e che l’array deve essere riallocato quando si riempie. Assicurati di creare gli oggetti StringBuilder/Buffer abbastanza grandi in origine, dove non devono essere ridimensionati costantemente ogni volta che viene chiamato.

Il ridimensionamento può diventare molto degenerato. In pratica, ridimensiona l’array di supporto a 2 volte la sua dimensione attuale ogni volta che deve essere espanso. Ciò può comportare l’allocazione di grandi quantità di RAM e non l’uso quando le classi StringBuilder/Buffer iniziano a ingrandirsi.

In Java String x = "A" + "B"; usa un StringBuilder dietro le quinte. Quindi per i casi semplici non c’è alcun vantaggio nel dichiarare il proprio. Ma se stai costruendo oggetti String che sono grandi, diciamo meno di 4k, quindi dichiarando StringBuilder sb = StringBuilder(4096); è molto più efficiente della concatenazione o usa il costruttore predefinito che ha solo 16 caratteri. Se la tua String sarà inferiore a 10k, inizializzala con il costruttore su 10k per essere sicura. Ma se si inizializza su 10k, si scrive 1 carattere più di 10k, esso verrà riallocato e copiato su un array 20k. Quindi inizializzare in alto è meglio che in basso.

Nel caso di ridimensionamento automatico, al 17 ° carattere l’array di supporto viene riallocato e copiato in 32 caratteri, al 33 ° carattere questo accade di nuovo e si arriva a riassegnare e copiare l’array in 64 caratteri. Puoi vedere come questo degeneri in molte riassegnazioni e copie che è quello che stai cercando di evitare di usare StringBuilder/Buffer in primo luogo.

Questo è dal codice sorgente JDK 6 per 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); } 

Una buona pratica è quella di inizializzare StringBuilder/Buffer un po ‘più grande di quello che pensate di cui avrete bisogno se non sapete a portata di mano quanto sarà grande la String ma potete indovinare. Un’allocazione di un po ‘più di memoria di cui hai bisogno sarà migliore di molte ridistribuzioni e copie.

Evita inoltre di inizializzare un StringBuilder/Buffer con una String quanto verrà allocata solo la dimensione della String + 16 caratteri, che nella maggior parte dei casi inizierà solo la degenerazione della ridestinazione e il ciclo di copia che stai cercando di evitare. Quanto segue è direttamente dal codice sorgente Java 6.

 public StringBuilder(String str) { super(str.length() + 16); append(str); } 

Se per caso finisci con un’istanza di StringBuilder/Buffer che non hai creato e non puoi controllare il costruttore chiamato, c’è un modo per evitare il degenerato riassegnare e copiare il comportamento. Chiama .ensureCapacity() con le dimensioni che vuoi garantire che la String risultante si adatti a.

Le alternative:

Come nota, se stai facendo una costruzione e una manipolazione delle String davvero pesanti , c’è un’alternativa molto più orientata alle prestazioni chiamata Ropes .

Un’altra alternativa consiste nel creare StringList mediante la sottoclassificazione di ArrayList e l’aggiunta di contatori per tenere traccia del numero di caratteri su ogni .append() e altre operazioni di mutazione dell’elenco, quindi eseguire l’override di .toString() per creare un StringBuilder delle dimensioni esatte necessarie e scorrere l’elenco e creare l’output, puoi persino rendere StringBuilder una variabile di istanza e “memorizzare” i risultati di .toString() e .toString() solo quando qualcosa cambia.

Inoltre, non dimenticare di String.format() quando si costruisce un output formattato fisso, che può essere ottimizzato dal compilatore in quanto lo rendono migliore.

Vuoi dire, per concatenazione?

Esempio di mondo reale: vuoi creare una nuova stringa tra tante altre .

Ad esempio per inviare un messaggio:

Stringa

 String s = "Dear " + user.name + "
" + " I saw your profile and got interested in you.
" + " I'm " + user.age + "yrs. old too"

StringBuilder

 String s = new StringBuilder().append.("Dear ").append( user.name ).append( "
" ) .append(" I saw your profile and got interested in you.
") .append(" I'm " ).append( user.age ).append( "yrs. old too") .toString()

O

 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 syntax è esattamente come con StringBuilder, gli effetti differiscono)

Di

StringBuffer vs. StringBuilder

Il primo è sincronizzato e dopo non lo è.

Quindi, se lo invochi più volte in un singolo thread (che è il 90% dei casi), StringBuilder verrà eseguito molto più velocemente perché non si fermerà per vedere se possiede il lock lock.

Quindi, è consigliabile utilizzare StringBuilder (a meno che, naturalmente, non ci sia più di un thread ad accedere allo stesso tempo, il che è raro)

String concatenazione delle String ( usando l’operatore + ) può essere ottimizzata dal compilatore per usare StringBuilder sotto, quindi, non è più qualcosa di cui preoccuparsi, nei vecchi giorni di Java, questo è qualcosa che tutti dicono che dovrebbero essere evitati a tutti i costi, perché ogni concatenazione ha creato un nuovo object String. I compilatori moderni non lo fanno più, ma è comunque buona norma usare StringBuilder nel caso in cui si usi un compilatore “vecchio”.

modificare

Solo per chi è curioso, questo è ciò che il compilatore fa per questa class:

 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."":()V 4: aload_0 5: new #2; //class java/lang/StringBuilder 8: dup 9: invokespecial #3; //Method java/lang/StringBuilder."":()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."":()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 } 

Le righe numerate 5 – 27 sono per la stringa denominata “letterale”

Le righe numerate 31-53 sono per la stringa denominata “builder”

Non c’è differenza, esattamente lo stesso codice viene eseguito per entrambe le stringhe.

 -------------------------------------------------- --------------------------------
                   String StringBuffer StringBuilder
 -------------------------------------------------- --------------------------------                 
 Area di stoccaggio |  Mucchio di heap di heap a stringa costante 
 Modificabile |  No (immutabile) Sì (mutabile) Sì (mutabile)
 Filo sicuro |  Sì Sì No
  Prestazioni |  Veloce Molto lento Veloce
 -------------------------------------------------- --------------------------------

Famiglia di spaghi

Stringa

La String class rappresenta stringhe di caratteri. Tutte le stringhe letterali nel programma Java, come "abc" sono implementate come istanze di questa class.

Gli oggetti stringa sono immutabili una volta creati non possiamo cambiare. (Le stringhe sono costanti )

  • Se una stringa viene creata utilizzando il metodo di costruzione o il metodo, tali stringhe verranno archiviate nella memoria di heap nonché in SringConstantPool . Ma prima di salvare in pool richiama il metodo intern() per verificare la disponibilità degli oggetti con lo stesso contenuto nel pool usando il metodo equals. Se String-copy è disponibile nel Pool, restituisce il riferimento. Altrimenti, l’object String viene aggiunto al pool e restituisce il riferimento.

    • Il linguaggio Java fornisce un supporto speciale per l’operatore di concatenazione di stringhe ( + ) e per la conversione di altri oggetti in stringhe. La concatenazione delle stringhe viene implementata tramite la class StringBuilder (o StringBuffer) e il relativo metodo 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); } 
  • I valori letterali stringa sono memorizzati in StringConstantPool .

     String onlyPool = "Yash"; 

StringBuilder e StringBuffer sono una sequenza mutabile di caratteri. Ciò significa che si può cambiare il valore di questi oggetti. StringBuffer ha gli stessi metodi di StringBuilder, ma ogni metodo in StringBuffer è sincronizzato, quindi è thread-safe.

  • I dati StringBuffer e StringBuilder possono essere creati solo utilizzando un nuovo operatore. Quindi, vengono memorizzati nella memoria Heap.

  • Le istanze di StringBuilder non sono sicure per l’uso da più thread. Se tale sincronizzazione è richiesta, si consiglia di utilizzare StringBuffer.

     StringBuffer threadSafe = new StringBuffer("Yash"); threadSafe.append(".M"); threadSafe.toString(); StringBuilder nonSync = new StringBuilder("Yash"); nonSync.append(".M"); nonSync.toString(); 
  • StringBuffer e StringBuilder hanno metodi speciali come., replace(int start, int end, String str) e reverse() .

    NOTA : StringBuffer e SringBuilder sono modificabili in quanto forniscono l’implementazione di Appendable Interface .


Quando usare quale.

  • Se non si intende modificare il valore ogni volta, è meglio utilizzare la String Class . Come parte di Generics se vuoi ordinare Comparable o confrontare un valore, allora vai su String Class .

     //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable Set set = new TreeSet(); set.add( threadSafe ); System.out.println("Set : "+ set); 
  • Se intendi modificare il valore ogni volta che vai su StringBuilder che è più veloce di StringBuffer. Se più thread stanno modificando il valore, vai per StringBuffer.

Inoltre, StringBuffer è thread-safe, che StringBuilder non è.

Quindi, in una situazione in tempo reale in cui diversi thread accedono ad essa, StringBuilder potrebbe avere un risultato indeterminato.

Si noti che se si utilizza Java 5 o versioni successive, è necessario utilizzare StringBuilder anziché StringBuffer . Dalla documentazione dell’API:

A partire dalla versione JDK 5, questa class è stata integrata con una class equivalente progettata per essere utilizzata da un singolo thread, StringBuilder . La class StringBuilder dovrebbe generalmente essere usata preferibilmente a questa, in quanto supporta tutte le stesse operazioni ma è più veloce, in quanto non esegue alcuna sincronizzazione.

In pratica, non lo utilizzerai quasi mai da più thread contemporaneamente, quindi la sincronizzazione StringBuffer da StringBuffer è quasi sempre inutile.

Personalmente, non penso che ci sia un uso del mondo reale per StringBuffer . Quando potrei voler comunicare tra più thread manipolando una sequenza di caratteri? Non sembra affatto utile, ma forse devo ancora vedere la luce 🙂

La differenza tra String e le altre due classi è che String è immutabile e le altre due sono classi mutabili.

Ma perché abbiamo due classi per lo stesso scopo?

Il motivo è che StringBuffer è thread sicuro e StringBuilder no. StringBuilder è una nuova class su StringBuffer Api ed è stato introdotto in JDK5 ed è sempre consigliato se si lavora in un ambiente a thread singolo poiché è molto Faster

Per i dettagli completi puoi leggere http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a—to-create-mutable-strings-in-java/

In java, String è immutabile. Essendo immutabili intendiamo che una volta creata una stringa, non possiamo cambiare il suo valore. StringBuffer è mutabile. Una volta creato un object StringBuffer, aggiungiamo semplicemente il contenuto al valore dell’object invece di creare un nuovo object. StringBuilder è simile a StringBuffer ma non è thread-safe. I metodi di StingBuilder non sono sincronizzati ma rispetto ad altre stringhe, lo Stringbuilder viene eseguito più velocemente. Puoi imparare la differenza tra String, StringBuilder e StringBuffer implementandoli.