Risposte:
Differenza di mutabilità:
String
è immutabile , se si tenta di modificare i loro valori, un altro oggetto viene creato, mentre StringBuffer
e StringBuilder
sono mutevoli in modo che possano cambiare i loro valori.
Differenza di sicurezza del thread:
La differenza tra StringBuffer
e StringBuilder
è che StringBuffer
è thread-safe. Quindi, quando l'applicazione deve essere eseguita solo in un singolo thread, è meglio utilizzarla StringBuilder
. StringBuilder
è più efficiente di StringBuffer
.
situazioni:
String
oggetto è immutabile.StringBuilder
è abbastanza buono.StringBuffer
perché StringBuffer
è sincrono, quindi si ha la sicurezza del thread.Strings
quando modifichiamo il valore, viene creato un altro oggetto. Il vecchio riferimento all'oggetto viene annullato in modo che possa essere raccolto dall'immondizia GC
o viene persino raccolto?
String
with StringBuilder
?
String
quando una struttura immutabile è appropriata; ottenere una nuova sequenza di caratteri da aString
può comportare una penalità delle prestazioni inaccettabile, sia nel tempo della CPU che nella memoria (ottenere sottostringhe è efficiente della CPU perché i dati non vengono copiati, ma ciò significa che può rimanere allocata una quantità potenzialmente maggiore di dati).StringBuilder
quando è necessario creare una sequenza di caratteri mutevole, in genere per concatenare più sequenze di caratteri insieme.StringBuffer
nelle stesse circostanze che si userebbero StringBuilder
, ma quando le modifiche alla stringa sottostante devono essere sincronizzate (perché diversi thread stanno leggendo / modificano il buffer di stringa).Vedi un esempio qui .
Le basi:
String
è una classe immutabile, non può essere cambiata.
StringBuilder
è una classe mutabile a cui è possibile aggiungere, i caratteri sostituiti o rimossi e infine convertiti in a String
StringBuffer
è la versione sincronizzata originale diStringBuilder
Dovresti preferire StringBuilder
in tutti i casi in cui hai un solo thread che accede al tuo oggetto.
I dettagli:
Nota anche che StringBuilder/Buffers
non sono magici, usano semplicemente un array come oggetto di supporto e che l'array deve essere riassegnato quando mai è pieno. Assicurati di creare i tuoi StringBuilder/Buffer
oggetti abbastanza grandi originariamente dove non devono essere costantemente ridimensionati ogni volta che .append()
vengono chiamati.
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 il mancato utilizzo quandoStringBuilder/Buffer
classi iniziano a crescere.
In Java String x = "A" + "B";
utilizza un StringBuilder
dietro le quinte. Quindi, per casi semplici, non vi è alcun vantaggio nel dichiarare il tuo. Ma se stai costruendo String
oggetti di grandi dimensioni, diciamo meno di 4k, allora dichiarare StringBuilder sb = StringBuilder(4096);
è molto più efficiente della concatenazione o usando il costruttore predefinito che ha solo 16 caratteri. Se il tuo String
sarà inferiore a 10k, inizializzalo con il costruttore su 10k per sicurezza. Ma se viene inizializzato su 10k, si scrive 1 carattere in più di 10k, verrà riassegnato e copiato in un array da 20k. Quindi l'inizializzazione in alto è meglio che in basso.
Nel caso di ridimensionamento automatico, al diciassettesimo carattere l'array di supporto viene riassegnato e copiato in 32 caratteri, al 33 ° carattere questo accade di nuovo e si ottiene di riassegnare e copiare l'array in 64 caratteri. Puoi vedere come questo degenera in molte riassegnazioni e copie, che è ciò che stai davvero cercando di evitare di utilizzare StringBuilder/Buffer
in primo luogo.
Questo proviene 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 è inizializzare StringBuilder/Buffer
un po 'più grande di quanto pensi di aver bisogno se non sai subito quanto String
sarà grande ma puoi indovinare. Un'allocazione di memoria leggermente superiore a quella necessaria sarà migliore di molte riassegnazioni e copie.
Fai anche attenzione a inizializzare un StringBuilder/Buffer
con un String
as che assegnerà solo la dimensione della stringa + 16 caratteri, che nella maggior parte dei casi avvierà solo il riassegnamento degenerato 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 StringBuilder/Buffer
che non hai creato e non riesci a controllare il costruttore chiamato, c'è un modo per evitare il degenerato riassegnare e copiare il comportamento. Chiama .ensureCapacity()
con le dimensioni che desideri per assicurarti che il risultato sia String
adatto.
Le alternative:
Proprio come una nota, se stai facendo costruzioni e manipolazioni davvero pesanti String
, c'è un'alternativa molto più orientata alle prestazioni chiamata Ropes .
Un'altra alternativa, è creare StringList
un'implementazione per sottoclasse ArrayList<String>
e aggiungere contatori per tenere traccia del numero di caratteri su ogni .append()
e altre operazioni di mutazione dell'elenco, quindi sovrascrivere .toString()
per creare una StringBuilder
dimensione esatta necessaria, scorrere l'elenco e costruire nell'output, puoi persino fare in modo che StringBuilder
una variabile di istanza e 'memorizzare nella cache' i risultati di .toString()
e debbano rigenerarla solo quando qualcosa cambia.
Inoltre, non dimenticare di String.format()
creare output formattati fissi, che possono essere ottimizzati dal compilatore mentre lo rendono migliore.
String x = "A" + "B";
davvero per essere un StringBuilder? Perché non dovrebbe semplicemente compilare String x = "AB";
, dovrebbe usare StringBuilder solo se i componenti non sono noti al momento della compilazione.
Intendi per concatenazione?
Esempio nel mondo reale: vuoi creare una nuova stringa da molte altre .
Ad esempio per inviare un messaggio:
Corda
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()
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 sintassi è esattamente come con StringBuilder, gli effetti differiscono)
Di
StringBuffer
vs. StringBuilder
Il primo è sincronizzato e successivamente non lo è.
Quindi, se lo invochi più volte in un singolo thread (che è il 90% dei casi), StringBuilder
funzionerà molto più velocemente perché non si fermerà per vedere se possiede il blocco thread.
Pertanto, si consiglia di utilizzare StringBuilder
(a meno che ovviamente non ci sia più di un thread ad accedervi contemporaneamente, il che è raro)
String
la concatenazione ( utilizzando l'operatore + ) può essere ottimizzata dal compilatore per essere utilizzata al di StringBuilder
sotto, quindi non è più qualcosa di cui preoccuparsi, nei giorni precedenti di Java, questo era qualcosa che tutti dicono che dovrebbe essere evitato a tutti i costi, perché ogni concatenazione creato un nuovo oggetto String. I compilatori moderni non lo fanno più, ma è comunque una buona pratica usare StringBuilder
nel caso in cui si utilizzi un compilatore "vecchio".
modificare
Solo per chi è curioso, ecco cosa fa il compilatore per questa 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
}
Le righe numerate da 5 a 27 sono per la stringa denominata "letterale"
Le righe numerate 31-53 sono per la stringa denominata "builder"
Non c'è alcuna differenza, esattamente lo stesso codice viene eseguito per entrambe le stringhe.
StringBuilder
concatenazione di stringhe per eseguire sul lato destro dell'assegnazione. Qualsiasi buona implementazione utilizzerà StringBuilder dietro le quinte come dici tu. Inoltre, il tuo esempio di "a" + "b"
verrebbe compilato in un singolo letterale "ab"
ma se lo utilizzassi StringBuilder
, comporterebbe due chiamate inutili a append()
.
"a"+"b"
ma per dire che cosa era una concatenazione di stringhe su di esso, lo cambio in modo esplicito. Quello che non dici è, perché non è una buona pratica farlo. Questo è esattamente ciò che fa un compilatore (moderno). @fuzzy, sono d'accordo, specialmente quando sai quale sarebbe la dimensione della stringa finale (aprox).
-------------------------------------------------- -------------------------------- String StringBuffer StringBuilder -------------------------------------------------- -------------------------------- Area di stoccaggio | Heap Heap di pool di stringhe costanti Modificabile | No (immutabile) Sì (modificabile) Sì (modificabile) Discussione sicura | Sì Sì No Prestazioni | Veloce Molto lento Veloce -------------------------------------------------- --------------------------------
synchronised
ed è per questo che .
Corda
La String class
rappresenta stringhe di caratteri. Tutti i valori letterali di stringa nel programma Java, ad esempio"abc"
implementati come istanze di questa classe.
Gli oggetti stringa sono immutabili una volta creati non possiamo cambiare. (Le stringhe sono costanti )
Se una stringa viene creata usando il costruttore o un metodo, allora quelle stringhe verranno memorizzati nella memoria heap così come SringConstantPool
. Ma prima di salvare nel pool, invoca il intern()
metodo per verificare la disponibilità degli oggetti con lo stesso contenuto nel pool utilizzando il metodo equals. Se String-copy è disponibile nel Pool, restituisce il riferimento. Altrimenti, l'oggetto String viene aggiunto al pool e restituisce il riferimento.
+
) e per la conversione di altri oggetti in stringhe. La concatenazione di stringhe viene implementata tramite la classe StringBuilder (o StringBuffer) e il suo 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 letterali stringa sono archiviati in StringConstantPool
.
String onlyPool = "Yash";
StringBuilder e StringBuffer sono sequenze di caratteri mutabili. 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 archiviati nella memoria dell'heap.
Le istanze di StringBuilder non sono sicure per l'uso da parte di più thread. Se è richiesta tale sincronizzazione, 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 stanno avendo alcuni 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 hai intenzione di cambiare il valore ogni volta, è meglio usare String Class
. Come parte di Generics, se desideri ordinare Comparable<T>
o confrontare un valore, procedi 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);
Se hai intenzione di modificare il valore ogni volta che vai per StringBuilder che è più veloce di StringBuffer. Se più thread stanno modificando il valore, procedi per StringBuffer.
Inoltre, StringBuffer
è thread-safe, che StringBuilder
non lo è.
Quindi in una situazione in tempo reale quando diversi thread vi accedono, StringBuilder
potrebbe avere un risultato indeterminato.
Si noti che se si utilizza Java 5 o versioni successive, è necessario utilizzare StringBuilder
invece di StringBuffer
. Dalla documentazione API:
Al rilascio JDK 5, questa classe è stato integrato con una classe equivalente progettato per essere utilizzato da un unico filo,
StringBuilder
. LaStringBuilder
classe dovrebbe generalmente essere usata preferibilmente a questa, poiché supporta tutte le stesse operazioni ma è più veloce, poiché non esegue alcuna sincronizzazione.
In pratica, non lo userai quasi mai da più thread contemporaneamente, quindi la sincronizzazione che StringBuffer
fa è quasi sempre un sovraccarico non necessario.
Personalmente, non penso che ci sia alcun uso nel mondo reale StringBuffer
. Quando mai vorrei 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
non lo è.
StringBuilder
è una nuova classe attiva StringBuffer Api
ed è stata introdotta JDK5
ed è sempre consigliata se si lavora in un ambiente a thread singolo poiché è moltoFaster
Per i dettagli completi è possibile leggere http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
In Java, String è immutabile. Essendo immutabili intendiamo che una volta creata una stringa, non possiamo cambiarne il valore. StringBuffer è modificabile. Una volta creato un oggetto StringBuffer, aggiungiamo semplicemente il contenuto al valore dell'oggetto invece di creare un nuovo oggetto. StringBuilder è simile a StringBuffer ma non è thread-safe. I metodi di StingBuilder non sono sincronizzati ma rispetto ad altre stringhe, Stringbuilder funziona più velocemente. Puoi imparare la differenza tra String, StringBuilder e StringBuffer implementandoli.