web-dev-qa-db-fra.com

Opérateur de concaténation (+) vs concat ()

Pour la concaténation de chaînes, nous pouvons utiliser soit l'opérateur concat(), soit l'opérateur concat (+).

J'ai essayé le test de performance suivant et j'ai trouvé que concat() est plus rapide et un moyen efficace de mémoire pour la concaténation de chaînes.

comparaison de concaténation de chaînes pour 100 000 fois:

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

Résultat

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

Si concat() est plus rapide que l'opérateur, alors quand utiliser l'opérateur de concaténation (+)?

28
Sunil Kumar Sahoo

La méthode concat produit toujours une nouvelle chaîne avec le résultat de la concaténation.

L'opérateur plus est soutenu par la création de StringBuilder, ajoutant toutes les valeurs de chaîne dont vous avez besoin et plus loin àString () l'appelant.

Donc, si vous devez concaténer deux valeurs, concat () sera un meilleur choix. Si vous devez concaténer 100 valeurs, vous devez utiliser l'opérateur plus ou utiliser explicitement StringBuilder (par exemple en cas d'ajout dans un cycle).

37
Artem

En fait, s1 + s2 et s1.concat (s2) sont très différents.

s1 + s2 est converti par javac en

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

Vous pouvez le voir si vous décompilez .class. Cette construction n'est pas très efficace; cela implique jusqu'à trois nouvelles allocations de caractères [] et trois opérations de copie de caractères [].

s1.concat (s2) est toujours un nouveau char [] + une opération de copie, voir 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);
}

Notez que new String (int, int, char []) est le constructeur privé du package de String. Il utilise directement char buf [], sans la copie habituelle pour garantir l'invisibilité de buf pour l'immuabilité de la chaîne.

12
Evgeniy Dorofeev

Votre test doit être exécuté pendant au moins 2 secondes avec chaque boucle dans une méthode distincte pour être significatif. Les tests courts peuvent être difficiles à reproduire et à comparer. D'après votre timing, il semble que vous utilisez Windows (c'est-à-dire parce que vos temps sont de 16 et 31 ms;) Essayez plutôt System.nanoTime (). Lorsque votre boucle itère plus de 10 000 fois, la méthode entière est compilée. Cela signifie que votre dernière méthode est déjà compilée au démarrage.

En réponse à votre question, la concaténation est légèrement plus rapide lors de l'ajout de deux chaînes. Cependant, il est livré avec une surcharge de frappe et conceptuelle qui est probablement beaucoup plus importante que le CPU que vous enregistrez. Même en vous basant sur vos tests qui se répètent 100 000 fois, cela permet d'économiser moins de 15 ms, et pourtant cela vous coûte beaucoup, bien plus que cela en votre temps (ce qui vaut probablement plus). Vous pourriez trouver dans une future version de la JVM, le la différence est toujours optimisée et la complexité de votre code est toujours là.


EDIT: Je n'ai pas remarqué que le résultat de la mémoire était suspect.

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

s'imprime lorsqu'il est exécuté avec -XX:-UseTLAB -mx1g

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

ce qui rend le rapport d'utilisation de la mémoire d'environ 2: 1. Dans la question d'origine, le résultat varie chaque fois que vous l'exécutez, parfois .concat() semble en utiliser davantage.

7
Peter Lawrey

Je crois que le "style" de concaténation va faire une différence.

Pour concat (), il crée en interne un nouveau tampon de tableau de caractères et renvoie une nouvelle chaîne basée sur ce tableau de caractères.

Pour l'opérateur +, le compilateur le traduit en fait pour utiliser StringBuffer/StringBuilder.

Par conséquent, si vous concaténez deux chaînes, concat () est certainement un meilleur choix car le nombre d'objets créés n'est que la chaîne de résultat (et le tampon de caractères utilisé à l'intérieur), tout en utilisant le + L'opérateur sera traduit en:

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

Une instance StringBuilder supplémentaire est créée.

Cependant, si vous concaténez, par exemple cinq chaînes consécutives, chaque concat () créera un nouvel objet String. Lors de l'utilisation de +, le compilateur traduira l'instruction en un seul StringBuilder avec plusieurs opérations d'ajout. Cela enregistre certainement beaucoup d'instances d'objets temporaires inutiles:

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

Vous pouvez toujours utiliser + si seulement vous utilisez> = Java 1.5 et vous ne déclarez pas votre chaîne de base (que vous voulez concaténer) en dehors de la boucle. En Java 1.5 cela entraîne la création de new StringBuilder et y travailler jusqu'à ce que votre chaîne soit terminée. C'est le moyen le plus rapide.

Quoi qu'il en soit - si vous êtes dans une boucle (et concaténation de chaînes avec +) - chaque itération de la boucle crée un new StringBuilder - ce n'est pas la meilleure idée. C'est donc là que vous devez forcer l'utilisation des classes StringBuilder ou StringBuffer (thread-safe).

Généralement, ce lien répond clairement à votre question et vous donne une connaissance complète:

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

0
dantuch

Bien que l'opérateur et la méthode fournissent la même sortie, la façon dont ils fonctionnent en interne diffère.

La méthode concat() qui concatène simplement str1 avec str2 et génère une chaîne, est plus efficace pour un petit nombre de concaténations.

Mais avec l'opérateur de concaténation '+', str1+=str2; sera interprété comme str1 = new StringBuilder().append(str1).append(str2).toString();

Vous pouvez utiliser la méthode concat lorsque vous utilisez moins de chaînes pour concaténer. Mais la méthode StringBuilder serait rapide en termes de performances, si vous utilisez un grand nombre de chaînes.

0