In che modo Java concatena la stringa usando “+”?

Ho letto sul modo in cui Java funziona con += operatore, usando StringBuilder .
È lo stesso con un’operazione ("a" + "b") ?

No. Non è lo stesso con StringBuilder che con "a" + "b" .

In Java, le istanze String sono immutabili.

Quindi, se lo fai:

 String c = "a" + "b"; 

Stai creando nuove stringhe ogni volta che ti concateni.

D’altra parte, StringBuilder è come un buffer che può crescere come necessario quando si aggiungono nuove stringhe.

 StringBuilder c = new StringBuilder(); c.append("a"); c.append("b"); // c is only created once and appended "a" and "b". 

La regola del pollice è (modificata grazie ai commenti che ho ricevuto):

Se si intende concatenare molto (ad esempio, concatenare all’interno di un ciclo o generare un grande XML formato da più variabili concatenate di stringhe), utilizzare StringBuilder. Altrimenti, la semplice concatenazione (usando l’operatore +) andrà bene.

Anche le ottimizzazioni del compilatore svolgono un ruolo enorme nella compilazione di questo tipo di codice.

Ecco ulteriori spiegazioni sull’argomento.

E altre domande StackOVerflow sul problema:

È meglio riutilizzare un object StringBuilder in un ciclo?

Qual è il modo migliore per build una stringa di elementi delimitati in Java?

StringBuilder vs String concatenation in toString () in Java

Se si combinano stringhe letterali (letteralmente "foo" + "bar" ), il compilatore lo fa in fase di compilazione, non in fase di runtime.

Se hai due stringhe non letterali e le unisci a + , il compilatore (Sun’s, comunque) userà un StringBuilder sotto le copertine, ma non necessariamente nel modo più efficiente. Ad esempio, se hai questo:

 String repeat(String a, int count) { String rv; if (count <= 0) { return ""; } rv = a; while (--count > 0) { rv += a; } return rv; } 

… ciò che il compilatore Sun produrrà effettivamente come bytecode è simile a questo:

 String repeat(String a, int count) { String rv; if (count <= 0) { return ""; } rv = a; while (--count > 0) { rv = new StringBuilder().append(rv).append(a).toString(); } return rv; } 

(Sì, davvero – vedere lo sassembly alla fine di questa risposta.) Si noti che ha creato un nuovo StringBuilder su ogni iterazione e quindi ha convertito il risultato in String . Questo è inefficiente (ma non importa a meno che non lo stiate facendo molto ) a causa di tutte le allocazioni temporanee della memoria: StringBuilder uno StringBuilder e il suo buffer, molto probabilmente rialloca il buffer nella prima append [se rv è più di 16 caratteri, che è la dimensione del buffer predefinita] e se non sul primo, quasi certamente sulla seconda append , quindi alloca una String alla fine – e poi fa di nuovo tutto alla successiva iterazione.

Potresti guadagnare efficienza, se necessario, riscrivendola per usare esplicitamente un StringBuilder :

 String repeat(String a, int count) { StringBuilder rv; if (count <= 0) { return ""; } rv = new StringBuilder(a.length() * count); while (count-- > 0) { rv.append(a); } return rv.toString(); } 

Lì abbiamo usato un StringBuilder esplicito e anche impostato la sua capacità di buffer iniziale per essere abbastanza grande da contenere il risultato. Questo è più efficiente in termini di memoria, ma, naturalmente, marginalmente meno chiaro per i manutentori del codice inesperti e marginalmente più di un dolore da scrivere. Quindi, se si riscontra un problema di prestazioni con un ciclo concat stringa stretto, questo potrebbe essere un modo per affrontarlo.

È ansible vedere questo StringBuilder sotto le copertine in azione con la seguente class di test:

 public class SBTest { public static final void main(String[] params) { System.out.println(new SBTest().repeat("testing ", 4)); System.exit(0); } String repeat(String a, int count) { String rv; if (count <= 0) { return ""; } rv = a; while (--count > 0) { rv += a; } return rv; } } 

… che disassembla (usando javap -c SBTest ) in questo modo:

 Compiled from "SBTest.java" public class SBTest extends java.lang.Object{ public SBTest(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static final void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: new #3; //class SBTest 6: dup 7: invokespecial #4; //Method "":()V 10: ldc #5; //String testing 12: iconst_4 13: invokevirtual #6; //Method repeat:(Ljava/lang/String;I)Ljava/lang/String; 16: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 19: iconst_0 20: invokestatic #8; //Method java/lang/System.exit:(I)V 23: return java.lang.String repeat(java.lang.String, int); Code: 0: iload_2 1: ifgt 7 4: ldc #9; //String 6: areturn 7: aload_1 8: astore_3 9: iinc 2, -1 12: iload_2 13: ifle 38 16: new #10; //class java/lang/StringBuilder 19: dup 20: invokespecial #11; //Method java/lang/StringBuilder."":()V 23: aload_3 24: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: aload_1 28: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: invokevirtual #13; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: astore_3 35: goto 9 38: aload_3 39: areturn } 

Si noti come viene creato un nuovo StringBuilder in ogni iterazione del ciclo e creato utilizzando la capacità del buffer predefinita.

Tutta questa roba di allocazione temporanea sembra brutta, ma ancora una volta, solo se hai a che fare con loop consistenti e / o stringhe sostanziali. Inoltre, quando viene eseguito il bytecode risultante, la JVM potrebbe ottimizzarla ulteriormente. Sun’s HotSpot JVM, ad esempio, è un compilatore di ottimizzazione JIT molto maturo. Una volta identificato il loop come hot spot, potrebbe trovare un modo per refactarlo. O no, ovviamente. 🙂

La mia regola generale è che mi preoccupo quando vedo un problema di prestazioni, o se so che sto facendo un sacco di concatenazioni ed è molto probabile che si tratti di un problema di prestazioni e il codice non sarà significativamente influenzato dal punto di vista della manutenibilità se uso invece un StringBuilder . La rabbiosa lega anti-prematura sarebbe probabilmente in disaccordo con me sul secondo di quelli. 🙂

Sì, è lo stesso, ma il compilatore può anche ottimizzare le concatenazioni di letterali prima di emettere il codice, quindi "a"+"b" può essere appena emesso come "ab" direttamente.

Per concatenare un numero fisso di stringhe in un’espressione con + , il compilatore produrrà il codice usando un singolo StringBuilder .

Ad esempio la linea

 String d = a + b + c; 

produce lo stesso bytecode della linea

 String d = new StringBuilder().append(a).append(b).append(c).toString(); 

quando compilato usando il compilatore javac. (Il compilatore Eclipse produce codice un po ‘più ottimizzato invocando il new StringBuilder(a) , risparmiando così una chiamata al metodo.)

Come accennato in altre risposte, il compilatore concatenerà stringhe letterali come "a" + "b" in un’unica stringa, producendo invece bytecode che contiene "ab" .

Come accennato ovunque in rete, non si dovrebbe usare + per creare una stringa all’interno di un ciclo , perché si sta copiando l’inizio della stringa più e più volte su nuove stringhe. In questa situazione dovresti usare un StringBuilder che dichiari fuori dal ciclo.

"a" + "b" operazione

Sebbene leggibili, facili da formattare e diretti, la concatenazione di stringhe con “+” è considerata negativa in Java.

Ogni volta che aggiungi qualcosa tramite ‘+’ (String.concat ()) viene creata una nuova Stringa, il vecchio contenuto di Stringa viene copiato, il nuovo contenuto viene aggiunto e la vecchia Stringa viene scartata. Più grande è il valore della stringa, più tempo è necessario: c’è più da copiare e più rifiuti vengono prodotti. Nota: se si concatenano solo poche (diciamo 3,4) stringhe e non si costruisce una stringa tramite un loop o si scrive semplicemente qualche applicazione di test, si potrebbe continuare a usare “+”

Utilizzando StringBuilder

Quando si esegue una estesa manipolazione delle stringhe (o aggiungendo un ciclo), è consigliabile sostituire “+” con StringBuilder . Gli oggetti intermedi menzionati in caso di “+” non vengono creati durante la chiamata al metodo append() .

Da notare anche le ottimizzazioni nel compilatore Sun Java, che crea automaticamente StringBuilders ( StringBuffers <5.0) quando vede concatenazioni di stringhe. Ma questo è solo il compilatore Sun Java.

Le stringhe sono più comunemente concatenate con l’operatore +, come in "Hello," + " world" + "!"

fonte