2012-01-06 2 views
23

Per la concatenazione di stringhe, è possibile utilizzare l'operatore concat() o concatenato (+).Operatore di concatenazione (+) vs. concat()

Ho provato il seguente test delle prestazioni e ho trovato concat() più veloce e un modo efficiente per la memorizzazione della stringa.

stringa di confronto concatenazione per 100.000 volte:

String str = null; 

//------------Using Concatenation operator------------- 
long time1 = System.currentTimeMillis(); 
long freeMemory1 = Runtime.getRuntime().freeMemory(); 

for(int i=0; i<100000; i++){ 
    str = "Hi"; 
    str = str+" Bye"; 
} 
long time2 = System.currentTimeMillis(); 
long freeMemory2 = Runtime.getRuntime().freeMemory(); 

long timetaken1 = time2-time1; 
long memoryTaken1 = freeMemory1 - freeMemory2; 
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + 
        " Memory Consumed =" + memoryTaken1); 

//------------Using Concat method------------- 
long time3 = System.currentTimeMillis(); 
long freeMemory3 = Runtime.getRuntime().freeMemory(); 
for(int j=0; j<100000; j++){ 
    str = "Hi"; 
    str = str.concat(" Bye"); 
} 
long time4 = System.currentTimeMillis(); 
long freeMemory4 = Runtime.getRuntime().freeMemory(); 
long timetaken2 = time4-time3; 
long memoryTaken2 = freeMemory3 - freeMemory4; 
System.out.println("Concat method :" + "Time taken =" + timetaken2 + 
        " Memory Consumed =" + memoryTaken2); 

Risultato

Concat operator: Time taken = 31; Memory Consumed = 2259096 
Concat method : Time taken = 16; Memory Consumed = 299592 

Se concat() è più veloce l'operatore poi quando dovremmo usare operatore di concatenamento (+)?

+1

Leggi: http://stackoverflow.com/questions/693597/is-there-a-difference-between-string-concat-and-the-operator-in-java e http://stackoverflow.com/questions/47605/java-string-concatenation –

+0

L'unica cosa che sembra diversa è quando la stringa che si sta aggiungendo ha una lunghezza pari a zero, ma restituisce l'originale invece di creare una nuova stringa. L'operatore + può essere un po 'costoso ... se stai facendo centinaia o migliaia di operazioni di costruzione di stringhe, cerca in StringBuffer.append(). È normale vedere un metodo creare un oggetto StringBuffer e quindi restituire o utilizzare ilBuffer.toString() alla fine. –

+0

@PankajKumar bene, probabilmente vuoi StringBuilder invece di StringBuffer – ymajoros

risposta

30

Il metodo concat produce sempre una nuova stringa con il risultato della concatenazione.

L'operatore plus è supportato dalla creazione di StringBuilder, aggiungendo tutti i valori di stringa necessari e ulteriori da toString().

Quindi, se è necessario concatenare due valori, concat() sarà una scelta migliore. Se è necessario concatenare 100 valori, è necessario utilizzare l'operatore plus o utilizzare StringBuilder in modo esplicito (ad esempio in caso di aggiunta in un ciclo).

+4

Il tuo ultimo commento vale solo per tutte le concatenazioni di stringhe che si trovano nella ** stessa espressione **. Quindi un 'StringBuilder' è usato per' x = a + b + c' (assumendo che tutti siano 'String's), ma due' StringBuilder's sono usati per 'x = a + b; x + = c; '. –

+1

Come addendum al collegamento di Artem, [questo] (http://www.znetdevelopment.com/blogs/2009/04/06/java-string-concatenation/) link, che sembra essere un post del blog di ritorno in ' 09 riguardo a questa domanda specifica. Speriamo che il collegamento fornisca un po 'più di contesto per le risposte e i commenti che Artem e TJ hanno fornito, anche se non riesco a verificare le asserzioni fatte nell'articolo poiché non sono certo esperto di Java ... – blahman

+2

Don' intendi 'esplicitamente usare StringBuilder' –

-2

In realtà, entrambi sono uguali. Se viene visualizzato il codice concat(String paramString), verrà restituito un nuovo oggetto di stringa e nell'operatore (+) verrà generato anche un nuovo oggetto stringa.

Se non si desidera creare un nuovo oggetto, utilizzare il generatore di stringhe per concatenare due stringhe.

+0

Per quanto riguarda (+), per lo più non è vero – dantuch

-1

In generale è una cattiva pratica concatenare le stringhe con + e con concat(). Se si desidera creare una stringa, utilizzare invece StringBuilder.

+0

Questa è ovviamente una risposta sbagliata. Ci sono molti casi in cui dovremmo usare + o concat() invece di StringBuilder/StringBuffer. –

+0

Il caso mostrato nella domanda era la concatenazione della stringa in un ciclo, in questo caso credo che StringBuilder sia il modo migliore per andare, non solo in Java. – Felype

3

Credo che lo "stile" di concatenazione farà la differenza.

Per concat(), crea internamente un nuovo buffer di array di caratteri e restituisce una nuova stringa basata su tale array di caratteri.

Per l'operatore +, il compilatore infatti lo traduce per utilizzare StringBuffer/StringBuilder.

Pertanto, se si concatenano due stringhe, concat() è sicuramente una scelta migliore poiché il numero di oggetti creati è solo il risultato String (e il buffer di caricamento utilizzato all'interno), mentre l'operatore + verrà tradotto in :

result = strA + strB; 
-- translate to --> 
result = new StringBuilder(strA).append(strB).toString(); 

Viene creata un'istanza di StringBuilder aggiuntiva.

Tuttavia, se si concatenano, ad esempio cinque stringhe di seguito, ogni concat() creerà un nuovo oggetto String. Durante l'utilizzo dell'operatore +, il compilatore tradurrà l'istruzione in un StringBuilder con più operazioni di aggiunta.E 'sicuramente risparmiare un sacco di inutili istanza di un oggetto temporaneo:

result = strA + strB + strC + strD + strE; 
-- translate to --> 
result = new StringBuilder(strA).append(strB).append(strC).append(strD).append(strE).toString(); 
+0

Il punto di pareggio è di circa quattro stringhe; l'efficienza relativa di '(String.valueOf (strA) .concat (strB)). concat (String.valueOf (strC) .concat (strD))' rispetto all'uso di un generatore di stringhe è all'incirca un errore. Per un massimo di otto stringhe, la concatenazione potrebbe essere più lenta, ma mai così enorme, ed è probabile che sia più veloce nei casi in cui sarebbe importante (finirà per copiare ogni carattere esattamente tre volte; 'StringBuilder' copierà ogni carattere due volte se non deve mai espandersi, ma se sono necessarie grandi espansioni sarà probabilmente necessario). – supercat

0

È possibile sempre uso + se solo si utilizzare> = Java 1.5 e si non dichiarare la stringa di base (che si desidera concatenare) al di fuori del ciclo. In Java 1.5 risulta nella creazione di new StringBuilder e lavorando su di esso fino al completamento della stringa. Questo è il modo più veloce.

In ogni caso, se si è in un ciclo (e concatenando stringhe con +), ogni iterazione del ciclo crea un new StringBuilder - non è la soluzione migliore. Quindi è qui che devi forzare l'uso delle classi StringBuilder o StringBuffer (thread-safe).

In generale, questo link risponde chiaramente alla tua domanda, e ti dà una conoscenza completa:

http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/

0

Sebbene sia l'operatore che il metodo stanno dando la stessa uscita, il loro modo di lavorare internamente è diversa.

Il metodo concat() che concatena solo str1 con str2 e restituisce una stringa, è più efficiente per un piccolo numero di concatenazioni.

Ma con operatore di concatenazione '+', str1+=str2; sarà interpretato come str1 = new StringBuilder().append(str1).append(str2).toString();

È possibile utilizzare il metodo concat quando si utilizza un numero minore di stringhe per concatenare. Ma il metodo StringBuilder sarebbe veloce in termini di prestazioni, se si utilizza un numero elevato di stringhe.

+0

Costruire un generatore di stringhe e usarlo ripetutamente è un bene per le prestazioni, ma creare un generatore di stringhe, usarlo per unire meno di quattro stringhe, e quindi abbandonarlo è controproducente. Sfortunatamente, il compilatore spesso usa e abbandona i builder di stringhe dopo averli usati per unire due stringhe. – supercat

7

Il test deve essere in esecuzione per almeno 2 secondi con ogni ciclo in un metodo separato per essere significativo. Brevi test possono essere difficili da riprodurre e confrontare. Dalla tua tempistica sembra che tu stia usando Windows (ad esempio perché i tempi sono 16 e 31 ms;) Prova invece System.nanoTime(). Quando il ciclo itera oltre 10.000 volte l'intero metodo viene compilato. Ciò significa che il tuo metodo successivo è già compilato quando viene avviato.

In risposta alla tua domanda concat è leggermente più veloce quando aggiungi due stringhe. Tuttavia, viene fornito con un overhead di digitazione e concettuale che è probabile che sia molto più grande della CPU che si salva. Anche in base ai test che si ripetono 100.000 volte si risparmia meno di 15 ms, eppure è costato molto, molto più di quel tempo (che probabilmente vale più). Si potrebbe trovare in una versione futura della JVM, la la differenza è sempre ottimizzata e la complessità del tuo codice è ancora lì.


MODIFICA: non ho notato che il risultato della memoria era sospetto.

String str = null; 

//------------Using Concatenation operator------------- 
long time1 = System.currentTimeMillis(); 
long freeMemory1 = Runtime.getRuntime().freeMemory(); 
for (int i = 0; i < 10000; i++) { 
    str = "Hi"; 
    str = str + " Bye"; 
} 
long time2 = System.currentTimeMillis(); 
long freeMemory2 = Runtime.getRuntime().freeMemory(); 

long timetaken1 = time2 - time1; 
long memoryTaken1 = freeMemory1 - freeMemory2; 
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + " Memory Consumed= " + memoryTaken1); 

str = null; 
//------------Using Concat method------------- 
long time3 = System.currentTimeMillis(); 
long freeMemory3 = Runtime.getRuntime().freeMemory(); 
for (int j = 0; j < 10000; j++) { 
    str = "Hi"; 
    str = str.concat(" Bye"); 

} 
long time4 = System.currentTimeMillis(); 
long freeMemory4 = Runtime.getRuntime().freeMemory(); 

long timetaken2 = time4 - time3; 
long memoryTaken2 = freeMemory3 - freeMemory4; 
System.out.println("Concat method :" + "Time taken =" + timetaken2 + " Memory Consumed= " + memoryTaken2); 

stampe quando eseguito con -XX:-UseTLAB -mx1g

Concat operator :Time taken =12 Memory Consumed= 1291456 
Concat method :Time taken =7 Memory Consumed= 560000 

rendendo il rapporto di utilizzo della memoria circa 2: 1. Nella domanda originale il risultato varia ogni volta che viene eseguito, a volte il .concat() sembra utilizzare di più.

+0

"eppure è costato molto, molto più di quello del tuo tempo (che probabilmente varrebbe di più)" qui costo significa digitazione e overhead concettuale? Ma se ignoriamo il vantaggio di 15ms, si può sostenere che l'utilizzo della memoria è 1/10 –

+0

@Naroji Non riesco a vedere come la memoria sia 1/10, 15ms è il tempo necessario per premere un tasto ed è banale in termini di tempo di sviluppo –

+0

la memoria consumata è 1/10, come indicato anche nella domanda. Operatore concatenato: tempo impiegato = 31 memoria consumata = "2,259,096" Metodo di concatenazione: tempo impiegato = 16 memoria consumata = "299,592" –

9

Infatti s1 + s2 e s1.concat (s2) sono molto diversi.

S1 + S2 viene convertito da javac in

(new StringBuilder(String.valueOf(s1)).append(s2).toString(); 

Lo si può vedere se si decompilare .class. Questo costrutto non è molto efficiente; coinvolge fino a tre nuove allocazioni char [] e tre operazioni di copia char [].

s1.concat (s2) è sempre un nuovo char [] operazione + una copia, vedere String.java

public String concat(String str) { 
    int otherLen = str.length(); 
    if (otherLen == 0) { 
     return this; 
    } 
    char buf[] = new char[count + otherLen]; 
    getChars(0, count, buf, 0); 
    str.getChars(0, otherLen, buf, count); 
    return new String(0, count + otherLen, buf); 
} 

Nota che new String (int, int, char []) è il pacchetto di private String costruttore. Utilizza char buf [] direttamente, senza la solita copia per garantire l'invisibilità del buf per l'immutabilità di String.

+0

Mi chiedo perché javac usi 'StringBuilder' anche combinando meno di quattro stringhe? Penso che 'String.valueOf (strA) .concat (strB) .concat (strC)' generi codice più compatto e - per ogni combinazione di lunghezze di stringa - più veloce di quello che 'strA + strB + strC' effettivamente genera, a meno che JITter sostituisca il codice che chiama 'StringBuilder' con qualcosa di più efficiente. – supercat