Java Language L'opérateur de concaténation de chaînes (+)


Exemple

Le symbole + peut signifier trois opérateurs distincts en Java:

  • S'il n'y a pas d'opérande avant le + , alors c'est l'opérateur unaire Plus.
  • S'il y a deux opérandes, ils sont tous deux numériques. alors c'est l'opérateur Addition binaire.
  • S'il y a deux opérandes et qu'au moins l'un d'eux est une String , alors il s'agit de l'opérateur de concaténation binaire.

Dans le cas simple, l'opérateur de concaténation joint deux chaînes pour donner une troisième chaîne. Par exemple:

String s1 = "a String";
String s2 = "This is " + s1;    // s2 contains "This is a String"

Lorsque l'un des deux opérandes n'est pas une chaîne, il est converti en une String comme suit:

  • Un opérande dont le type est un type primitif est converti comme en appelant toString() sur la valeur encadrée.

  • Un opérande dont le type est un type de référence est converti en appelant la toString() l'opérande. Si l'opérande est null ou si la toString() renvoie null , le littéral de chaîne "null" est utilisé à la place.

Par exemple:

int one = 1;
String s3 = "One is "  + one;         // s3 contains "One is 1"
String s4 = null + " is null";        // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
                                      // "{} is [I@xxxxxxxx"

L'explication de l'exemple s5 est que la toString() sur les types de tableau est héritée de java.lang.Object et que le comportement consiste à produire une chaîne composée du nom du type et du code de hachage de l'identité de l'objet.

L'opérateur Concatenation est spécifié pour créer un nouvel objet String , sauf dans le cas où l'expression est une expression constante. Dans ce dernier cas, l'expression est évaluée au type de compilation et sa valeur d'exécution est équivalente à un littéral de chaîne. Cela signifie qu'il n'y a pas de surcharge d'exécution lors du fractionnement d'un littéral de chaîne longue comme ceci:

String typing = "The quick brown fox " +
                "jumped over the " +
                "lazy dog";           // constant expression

Optimisation et efficacité

Comme indiqué ci-dessus, à l'exception des expressions constantes, chaque expression de concaténation de chaîne crée un nouvel objet String . Considérez ce code:

public String stars(int count) {
    String res = "";
    for (int i = 0; i < count; i++) {
        res = res + "*";
    }
    return res;
}

Dans la méthode ci-dessus, chaque itération de la boucle créera une nouvelle String un caractère plus longue que l'itération précédente. Chaque concaténation copie tous les caractères des chaînes d'opérandes pour former la nouvelle String . Ainsi, les stars(N) vont:

  • créer N nouveaux objets String , et jeter tous sauf le dernier,
  • copier N * (N + 1) / 2 caractères, et
  • générer O(N^2) octets de déchets.

C'est très cher pour les gros N En effet, tout code concaténant des chaînes dans une boucle est susceptible d'avoir ce problème. Une meilleure façon d'écrire ceci serait la suivante:

public String stars(int count) {
    // Create a string builder with capacity 'count' 
    StringBuilder sb = new StringBuilder(count);
    for (int i = 0; i < count; i++) {
        sb.append("*");
    }
    return sb.toString();
}

Idéalement, vous devez définir la capacité du StringBuilder , mais si cela est impossible, la classe se développera automatiquement le tableau de sauvegarde que le constructeur utilise pour tenir des caractères. (Remarque: l'implémentation étend le tableau de support de manière exponentielle. Cette stratégie conserve cette quantité de caractères à un O(N) plutôt qu'à un O(N^2) .)

Certaines personnes appliquent ce modèle à toutes les concaténations de chaînes. Cependant, cela n'est pas nécessaire car le JLS permet à un compilateur Java d'optimiser les concaténations de chaînes dans une seule expression. Par exemple:

String s1 = ...;
String s2 = ...;    
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";

sera généralement optimisé par le compilateur bytecode à quelque chose comme ça;

StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();

(Le compilateur JIT peut optimiser cela plus loin s'il peut en déduire que s1 ou s2 ne peut pas être null .) Mais notez que cette optimisation n'est autorisée que dans une seule expression.

En bref, si vous êtes préoccupé par l'efficacité des concaténations de chaînes:

  • Effectuez une optimisation manuelle si vous effectuez une concaténation répétée dans une boucle (ou similaire).
  • Ne pas optimiser manuellement une seule expression de concaténation.