Qual è la differenza principale tra StringBuffer
e StringBuilder
? Ci sono problemi di prestazioni quando si decide su uno di questi?
Qual è la differenza principale tra StringBuffer
e StringBuilder
? Ci sono problemi di prestazioni quando si decide su uno di questi?
Risposte:
StringBuffer
è sincronizzato, StringBuilder
non lo è.
StringBuilder
è più veloce di StringBuffer
perché non lo è synchronized
.
Ecco un semplice test di riferimento:
public class Main {
public static void main(String[] args) {
int N = 77777777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = N; i --> 0 ;) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = N; i > 0 ; i--) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
}
}
Una corsa di prova fornisce i numeri di 2241 ms
for StringBuffer
vs 753 ms
for StringBuilder
.
--> 0
in loop. Mi ci è voluto un momento per capire cosa significa. È qualcosa che viene effettivamente utilizzato nella pratica invece della solita ...; i > 0; i--
sintassi?
i -->
davvero fastidioso per la sintassi ... all'inizio pensavo che fosse una freccia a causa dei commenti sull'arte ASCII.
main()
Inoltre, il tuo benchmark non è giusto. Non c'è riscaldamento.
Fondamentalmente, i StringBuffer
metodi sono sincronizzati mentre StringBuilder
non lo sono.
Le operazioni sono "quasi" uguali, ma l'utilizzo di metodi sincronizzati in un singolo thread è eccessivo.
È praticamente tutto.
Citazione dall'API StringBuilder :
Questa classe [StringBuilder] fornisce un'API compatibile con StringBuffer, ma senza alcuna garanzia di sincronizzazione . Questa classe è progettata per essere utilizzata come sostituto drop-in per StringBuffer in luoghi in cui il buffer di stringa veniva utilizzato da un singolo thread (come generalmente accade). Laddove possibile, si consiglia di utilizzare questa classe preferibilmente a StringBuffer poiché sarà più veloce nella maggior parte delle implementazioni.
Quindi è stato fatto per sostituirlo.
Lo stesso è successo con Vector
e ArrayList
.
Hashtable
e HashMap
.
Ma hai bisogno di ottenere la chiara differenza con l'aiuto di un esempio?
StringBuffer o StringBuilder
Basta usare a StringBuilder
meno che non si stia davvero cercando di condividere un buffer tra i thread. StringBuilder
è il fratello minore non sincronizzato (meno sovraccarico = più efficiente) della StringBuffer
classe sincronizzata originale .
StringBuffer
è venuto per primo. Sun si preoccupava della correttezza in tutte le condizioni, quindi l'hanno sincronizzata per renderla thread-safe per ogni evenienza.
StringBuilder
è venuto dopo. La maggior parte degli usi di StringBuffer
era a thread singolo e pagava inutilmente il costo della sincronizzazione.
Poiché StringBuilder
è un rimpiazzo per StringBuffer
senza la sincronizzazione, non ci sarebbero differenze tra gli esempi.
Se si sta tentando di condivisione tra i thread, è possibile utilizzare StringBuffer
, ma considerare se la sincronizzazione di livello superiore è necessario, ad esempio, forse invece di usare StringBuffer, si dovrebbe sincronizzare i metodi che utilizzano lo StringBuilder.
Per prima cosa vediamo le somiglianze : Sia StringBuilder che StringBuffer sono mutabili. Ciò significa che puoi modificarne il contenuto, con nella stessa posizione.
Differenze : StringBuffer è anche mutabile e sincronizzato. Dove come StringBuilder è modificabile ma non sincronizzato per impostazione predefinita.
Significato della sincronizzazione (sincronizzazione) : quando una cosa è sincronizzata, è possibile accedere a più thread e modificarla senza alcun problema o effetto collaterale. StringBuffer è sincronizzato, quindi puoi usarlo con più thread senza alcun problema.
Quale usare quando? StringBuilder: quando hai bisogno di una stringa, che può essere modificabile, e solo un thread la sta accedendo e modificando. StringBuffer: quando hai bisogno di una stringa, che può essere modificabile, e più thread accedono e la modificano.
Nota : non utilizzare StringBuffer inutilmente, ovvero non utilizzarlo se un solo thread lo sta modificando e accedendo perché ha un sacco di codice di blocco e sblocco per la sincronizzazione che impiegherà inutilmente tempo della CPU. Non utilizzare i blocchi a meno che non sia necessario.
Nei thread singoli, StringBuffer non è significativamente più lento di StringBuilder , grazie alle ottimizzazioni JVM. E nel multithreading, non è possibile utilizzare in sicurezza StringBuilder.
Ecco il mio test (non un benchmark, solo un test):
public static void main(String[] args) {
String withString ="";
long t0 = System.currentTimeMillis();
for (int i = 0 ; i < 100000; i++){
withString+="some string";
}
System.out.println("strings:" + (System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuffer buf = new StringBuffer();
for (int i = 0 ; i < 100000; i++){
buf.append("some string");
}
System.out.println("Buffers : "+(System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuilder building = new StringBuilder();
for (int i = 0 ; i < 100000; i++){
building.append("some string");
}
System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}
Risultati:
stringhe: 319740
Buffer: 23
Costruttore: 7!
Quindi i Builders sono più veloci dei Buffer e WAY più veloci della concatenazione delle stringhe. Ora usiamo un Executor per più thread:
public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
//With Buffer
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(buffer));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Buffer : "+ AppendableRunnable.time);
//With Builder
AppendableRunnable.time = 0;
executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(builder));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Builder: "+ AppendableRunnable.time);
}
static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // code reduced from Official Javadoc for Executors
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (Exception e) {}
}
}
class AppendableRunnable<T extends Appendable> implements Runnable {
static long time = 0;
T appendable;
public AppendableRunnable(T appendable){
this.appendable = appendable;
}
@Override
public void run(){
long t0 = System.currentTimeMillis();
for (int j = 0 ; j < 10000 ; j++){
try {
appendable.append("some string");
} catch (IOException e) {}
}
time+=(System.currentTimeMillis() - t0);
}
}
Ora StringBuffers impiega 157 ms per 100000 accodamenti. Non è lo stesso test, ma rispetto ai precedenti 37 ms, puoi tranquillamente supporre che le aggiunte di StringBuffers siano più lente con l'uso del multithreading . La ragione è che il JIT / hotspot / compilatore / qualcosa rende ottimizzazioni quando rileva che non v'è alcuna necessità di controllare le serrature.
Ma con StringBuilder, hai java.lang.ArrayIndexOutOfBoundsException , perché un thread simultaneo tenta di aggiungere qualcosa dove non dovrebbe.
La conclusione è che non devi inseguire StringBuffers. E dove hai i fili, pensa a cosa stanno facendo, prima di provare a guadagnare qualche nanosecondo.
withString+="some string"+i+" ; ";
non è equivalente agli altri due loop e non è quindi un confronto equo.
StringBuilder è stato introdotto in Java 1.5, quindi non funzionerà con le JVM precedenti.
Dai Javadocs :
La classe StringBuilder fornisce un'API compatibile con StringBuffer, ma senza garanzia di sincronizzazione. Questa classe è progettata per essere utilizzata come sostituto drop-in per StringBuffer in luoghi in cui il buffer di stringa veniva utilizzato da un singolo thread (come generalmente accade). Laddove possibile, si consiglia di utilizzare questa classe preferibilmente a StringBuffer poiché sarà più veloce nella maggior parte delle implementazioni.
StringBuilder
.
Domanda abbastanza buona
Ecco le differenze, ho notato:
StringBuffer: -
StringBuffer is synchronized
StringBuffer is thread-safe
StringBuffer is slow (try to write a sample program and execute it, it will take more time than StringBuilder)
StringBuilder: -
StringBuilder is not synchronized
StringBuilder is not thread-safe
StringBuilder performance is better than StringBuffer.
Cosa comune: -
Entrambi hanno gli stessi metodi con le stesse firme. Entrambi sono mutabili.
StringBuffer
StringBuilder
StringBuffer
senza altre modificheappend
due volte, o append
e toString
non non è sicuro.
StringBuilder non è thread-safe. String Buffer è. Maggiori informazioni qui .
EDIT: Per quanto riguarda le prestazioni, dopo l' attivazione dell'hotspot , StringBuilder è il vincitore. Tuttavia, per piccole iterazioni, la differenza di prestazioni è trascurabile.
StringBuilder
e StringBuffer
sono quasi gli stessi. La differenza è che StringBuffer
è sincronizzato e StringBuilder
non lo è. Sebbene, StringBuilder
sia più veloce di StringBuffer
, la differenza nelle prestazioni è molto piccola. StringBuilder
è un sostituto di SUN di StringBuffer
. Evita solo la sincronizzazione da tutti i metodi pubblici. Invece, la loro funzionalità è la stessa.
Esempio di buon utilizzo:
Se il testo cambierà e verrà utilizzato da più thread, è meglio utilizzarlo StringBuffer
. Se il testo cambierà ma viene utilizzato da un singolo thread, utilizzare StringBuilder
.
StringBuffer
StringBuffer è mutabile significa che è possibile modificare il valore dell'oggetto. L'oggetto creato tramite StringBuffer è archiviato nell'heap. StringBuffer ha gli stessi metodi di StringBuilder, ma ogni metodo in StringBuffer è sincronizzato, ovvero StringBuffer è thread-safe.
per questo motivo non consente a due thread di accedere contemporaneamente allo stesso metodo. È possibile accedere a ciascun metodo da un thread alla volta.
Ma essere thread-safe ha anche degli svantaggi in quanto le prestazioni di StringBuffer colpiscono grazie alla proprietà thread-safe. Pertanto StringBuilder è più veloce di StringBuffer quando chiama gli stessi metodi di ogni classe.
Il valore StringBuffer può essere modificato, significa che può essere assegnato al nuovo valore. Oggi è una domanda di intervista più comune, le differenze tra le classi di cui sopra. String Buffer può essere convertito nella stringa utilizzando il metodo toString ().
StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .
demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilder è uguale a StringBuffer, ovvero memorizza l'oggetto nell'heap e può anche essere modificato. La principale differenza tra StringBuffer e StringBuilder è che StringBuilder non è anche sicuro per i thread. StringBuilder è veloce in quanto non è thread-safe.
StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified
demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder
String
è un immutabile.
StringBuffer
è mutabile e sincronizzato.
StringBuilder
è anche mutabile ma non è sincronizzato.
Il javadoc spiega la differenza:
Questa classe fornisce un'API compatibile con StringBuffer, ma senza alcuna garanzia di sincronizzazione. Questa classe è progettata per essere utilizzata come sostituto drop-in per StringBuffer in luoghi in cui il buffer di stringa veniva utilizzato da un singolo thread (come generalmente accade). Laddove possibile, si consiglia di utilizzare questa classe preferibilmente a StringBuffer poiché sarà più veloce nella maggior parte delle implementazioni.
StringBuilder
(introdotto in Java 5) è identico a StringBuffer
, tranne che i suoi metodi non sono sincronizzati. Ciò significa che ha prestazioni migliori rispetto a quest'ultimo, ma lo svantaggio è che non è thread-safe.
Leggi il tutorial per maggiori dettagli.
Un semplice programma che illustra la differenza tra StringBuffer e StringBuilder:
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
StringBuffer viene utilizzato per memorizzare stringhe di caratteri che verranno modificate (gli oggetti String non possono essere modificati). Si espande automaticamente secondo necessità. Classi correlate: String, CharSequence.
StringBuilder è stato aggiunto in Java 5. È identico sotto tutti gli aspetti a StringBuffer, tranne per il fatto che non è sincronizzato, il che significa che se più thread accedono ad esso contemporaneamente, potrebbero esserci problemi. Per i programmi a thread singolo, il caso più comune, evitando l'overhead della sincronizzazione rende StringBuilder molto più veloce.
StringBuilder
solito sono locali a un metodo, dove sono visibili a un solo thread.
StringBuffer
è sincronizzato, ma StringBuilder
non lo è. Di conseguenza, StringBuilder
è più veloce di StringBuffer
.
StringBuffer è modificabile. Può cambiare in termini di lunghezza e contenuto. StringBuffer sono thread-safe, nel senso che hanno metodi sincronizzati per controllare l'accesso in modo che solo un thread possa accedere al codice sincronizzato di un oggetto StringBuffer alla volta. Pertanto, gli oggetti StringBuffer sono generalmente sicuri da usare in un ambiente multi-thread in cui più thread potrebbero tentare di accedere allo stesso oggetto StringBuffer contemporaneamente.
StringBuilder La classe StringBuilder è molto simile a StringBuffer, tranne per il fatto che il suo accesso non è sincronizzato, quindi non è thread-safe. Non essendo sincronizzato, le prestazioni di StringBuilder possono essere migliori di StringBuffer. Pertanto, se si lavora in un ambiente a thread singolo, l'utilizzo di StringBuilder anziché StringBuffer può comportare un aumento delle prestazioni. Ciò vale anche per altre situazioni come una variabile locale StringBuilder (ovvero una variabile all'interno di un metodo) in cui solo un thread accederà a un oggetto StringBuilder.
StringBuffer:
StringBuilder
String c = a + b
equivale a String c = new StringBuilder().append(a).append(b).toString()
, quindi non è più veloce. È solo che ne crei uno nuovo per ogni assegnazione di stringa, mentre potresti averne solo una ( String d = a + b; d = d + c;
è il String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();
momento in cui StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();
salverebbe un'istanza di StringBuilder).
String-Builder :
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
String-Buffer
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
Si consiglia di utilizzare StringBuilder quando possibile perché è più veloce di StringBuffer. Tuttavia, se è necessaria la sicurezza del thread, l'opzione migliore è oggetti StringBuffer.
Migliore utilizzo in StringBuilder
quanto non sincronizzato e offre quindi prestazioni migliori. StringBuilder
è un rimpiazzo sostitutivo del vecchio StringBuffer
.
StringBu(ff|ild)er
è una variabile locale utilizzata solo da un singolo thread.
Dato che StringBuffer
è sincronizzato, ha bisogno di qualche sforzo extra, quindi basato sulla perforazione, è un po 'più lento di StringBuilder
.
Non ci sono differenze di base tra StringBuilder
e StringBuffer
, esistono solo alcune differenze tra di loro. Nei StringBuffer
metodi sono sincronizzati. Ciò significa che alla volta solo un thread può operare su di essi. Se è presente più di un thread, il secondo thread dovrà attendere il termine del primo e il terzo dovrà attendere il completamento del primo e del secondo e così via. Questo rende il processo molto lento e quindi le prestazioni nel caso diStringBuffer
sono basse.
D'altra parte, StringBuilder
non è sincronizzato. Ciò significa che contemporaneamente più thread possono operare sullo stesso StringBuilder
oggetto contemporaneamente. Questo rende il processo molto veloce e quindi le prestazioni StringBuilder
sono elevate.
A String
è un oggetto immutabile, il che significa che il valore non può essere modificato mentre StringBuffer
è mutabile.
Il StringBuffer
è sincronizzata quindi thread-safe che StringBuilder
non e adatti sono solo a istanze thread singolo.
La differenza principale è che StringBuffer
è sincronizzata ma non lo StringBuilder
è. Se è necessario utilizzare più di un thread, si consiglia StringBuffer, ma, secondo la velocità di esecuzione, StringBuilder
è più veloce di StringBuffer
, perché non è sincronizzato.
Controllare gli interni del metodo di aggiunta sincronizzato di StringBuffer
e il metodo di aggiunta non sincronizzato di StringBuilder
.
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
Poiché append è synchronized
, StringBuffer
ha un sovraccarico di prestazioni rispetto allo StrinbBuilder
scenario multi-threading. Finché non si condivide il buffer tra più thread, utilizzare StringBuilder
, che è veloce a causa dell'assenza di synchronized
metodi in append.
Ecco il risultato del test delle prestazioni per String vs StringBuffer vs StringBuilder . Alla fine, StringBuilder ha vinto il test. Vedi sotto per il codice di prova e il risultato.
Codice :
private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;
long start = 0;
// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");
// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");
}
Risultato :
100000 iterazioni per l'aggiunta di un singolo testo
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000 iterazioni per l'aggiunta di un singolo testo
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBuffer è sincronizzato e thread-safe, StringBuilder non è sincronizzato e più veloce.