String, StringBuffer e StringBuilder


Risposte:


378

Differenza di mutabilità:

Stringè immutabile , se si tenta di modificare i loro valori, un altro oggetto viene creato, mentre StringBuffere StringBuildersono mutevoli in modo che possano cambiare i loro valori.

Differenza di sicurezza del thread:

La differenza tra StringBuffere 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:

  • Se la tua stringa non cambierà, usa una classe String perché un Stringoggetto è immutabile.
  • Se la tua stringa può cambiare (esempio: molta logica e operazioni nella costruzione della stringa) e vi si accederà da un singolo thread, usare a StringBuilderè abbastanza buono.
  • Se la stringa può cambiare e sarà possibile accedervi da più thread, utilizzare un StringBufferperché StringBufferè sincrono, quindi si ha la sicurezza del thread.

16
Inoltre, l'utilizzo di String per operazioni logiche è piuttosto lento e non è affatto consigliato, poiché JVM converte String in StringBuffer nel bytecode. Un sacco di overhead è sprecato per la conversione da String a StringBuffer e poi di nuovo in String.
Pieter van Niekerk,

2
Quindi, Stringsquando modifichiamo il valore, viene creato un altro oggetto. Il vecchio riferimento all'oggetto viene annullato in modo che possa essere raccolto dall'immondizia GCo viene persino raccolto?
Harsh Vardhan,

@PietervanNiekerk Cosa intendi con operazioni logiche?
emlai,

le operazioni logiche intendo sono stringhe di base, ora una cosa che vorrei chiedere, come affermato da @Peter, dovremmo iniziare a utilizzare StringBuffer invece su String in tutti i casi o ci sono alcuni casi specifici?
Java Dragon,

@bakkal Posso usare tutti i metodi di Stringwith StringBuilder?
roottraveller,

47
  • Si utilizza Stringquando 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).
  • Si utilizza StringBuilderquando è necessario creare una sequenza di caratteri mutevole, in genere per concatenare più sequenze di caratteri insieme.
  • Si usa StringBuffernelle 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 .


2
conciso, ma incompleto, manca il motivo fondamentale per utilizzare StringBuilder / Buffer, ovvero ridurre o eliminare la riassegnazione e la copia dell'array del normale comportamento di concatenazione di stringhe.

1
"Usa String quando hai a che fare con stringhe immutabili" - non ha senso. Le istanze di String SONO immutabili, quindi forse il commento dovrebbe leggere "Usa String quando l'utilizzo della memoria a causa dell'immutabilità non ha importanza". La risposta accettata copre le basi piuttosto bene.
fooMonster,

28

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 StringBuilderin tutti i casi in cui hai un solo thread che accede al tuo oggetto.

I dettagli:

Nota anche che StringBuilder/Buffersnon 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/Bufferoggetti 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 StringBuilderdietro le quinte. Quindi, per casi semplici, non vi è alcun vantaggio nel dichiarare il tuo. Ma se stai costruendo Stringoggetti 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 Stringsarà 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/Bufferin 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/Bufferun po 'più grande di quanto pensi di aver bisogno se non sai subito quanto Stringsarà 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/Buffercon un Stringas 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/Bufferche 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 Stringadatto.

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 StringListun'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 StringBuilderdimensione esatta necessaria, scorrere l'elenco e costruire nell'output, puoi persino fare in modo che StringBuilderuna 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.


1
Compilare 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.
Matt Greer,

potrebbe ottimizzare le costanti String, non ricordo dall'ultima volta che ho decompilato il codice byte, ma so che se ci sono delle variabili, utilizzerà sicuramente un'implementazione StringBuilder. Puoi scaricare il codice sorgente JDK e scoprirlo da solo. "A" + "B" è sicuramente un esempio inventato.

Mi stavo chiedendo di String.format (). Non l'ho mai visto davvero usato nei progetti. Di solito è StringBuilder. Bene, di solito è in realtà "A" + "B" + "C" perché le persone sono pigre;) tendevo a usare sempre StringBuilder, anche se fossero state concatenate solo due stringhe, perché in futuro, forse più stringhe sarebbero state aggiunte . Non ho mai usato String.format () principalmente perché non mi ero mai ricordato di quale JDK fosse stato introdotto - vedo che è JDK1.5, lo userei a favore delle altre opzioni.
Jamiebarrow,

9

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), StringBuilderfunzionerà 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)

Stringla concatenazione ( utilizzando l'operatore + ) può essere ottimizzata dal compilatore per essere utilizzata al di StringBuildersotto, 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 StringBuildernel 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.


2
questo è davvero un cattivo esempio. Inizializzare StringBuilder con "Dear" significa che il primo .append () causerà una riallocazione e una copia. Negare completamente qualsiasi efficienza che si sta tentando di ottenere rispetto alla concatenazione "normale". Un esempio migliore sarebbe quello di crearlo con una dimensione iniziale che conterrà l'intero contenuto della stringa finale.

1
In genere NON è una buona pratica utilizzare una StringBuilderconcatenazione 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().
Mark Peters

@Mark Non intendevo usare, "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).
OscarRyz,

1
Non penso che sia una cattiva pratica, ma certamente non vorrei alcuna raccomandazione per farlo in generale. È goffo e difficile da leggere, e troppo prolisso. Inoltre, incoraggia errori come il tuo in cui stai rompendo due letterali che altrimenti potrebbero essere compilati come uno. Solo se la profilazione mi avesse detto che avrebbe fatto la differenza, avrei fatto a modo tuo.
Mark Peters,

@Mark Capito. Stavo pensando di più nel "grosso pezzo di codice come un modello" e non proprio in ogni normale stringa letterale. Ma sì, sono d'accordo, dal momento che fanno la stessa cosa al giorno d'oggi, non ha senso (10 anni fa era un motivo per rifiutare una modifica in una revisione del codice) :)
OscarRyz

8
-------------------------------------------------- --------------------------------
                  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
-------------------------------------------------- --------------------------------

Perché le prestazioni di String sono veloci e le prestazioni di StringBuffer sono molto lente?
gaurav,

1
@gaurav puoi leggere il suo codice sorgente, tutti i metodi in StringBuffer è synchroniseded è per questo che .
Sentito

8

Famiglia di stringhe

Corda

La String classrappresenta 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.

    • 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 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.


4

Inoltre, StringBufferè thread-safe, che StringBuildernon lo è.

Quindi in una situazione in tempo reale quando diversi thread vi accedono, StringBuilderpotrebbe avere un risultato indeterminato.


3

Si noti che se si utilizza Java 5 o versioni successive, è necessario utilizzare StringBuilderinvece 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. La StringBuilderclasse 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 StringBufferfa è quasi sempre un sovraccarico non necessario.


3

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 :)


3

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 StringBufferThread è sicuro e StringBuildernon lo è. StringBuilderè una nuova classe attiva StringBuffer Apied è stata introdotta JDK5ed è 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/


2

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.