1. Immuabilité des chaînes : alliée ou ennemie ?
En Java, la classe String est immutable. Cela signifie qu’une fois créée, une chaîne ne peut pas être modifiée. Chaque fois que vous « modifiez » une chaîne, par exemple en lui ajoutant quelque chose via + ou concat(), un nouvel objet est en réalité créé, et l’ancien part aux oubliettes (et en mémoire, au garbage collector).
Exemple :
String s = "Hello";
s = s + " world!";
System.out.println(s); // Hello world!
On dirait que la chaîne s a changé, mais en réalité une nouvelle chaîne "Hello world!" a été créée, tandis que l’ancienne "Hello" reste en mémoire jusqu’à ce que le garbage collector la libère. Si ces opérations sont nombreuses — par exemple dans une boucle —, le programme commence à ralentir et à consommer de la mémoire inutilement.
Imaginez que vous construisez une tour de briques, et qu’à chaque fois que vous voulez ajouter une nouvelle brique, vous deviez reconstruire toute la tour. Pas très économique, n’est‑ce pas ? C’est ainsi que fonctionne un String classique en Java lors de modifications fréquentes.
2. StringBuilder : constructeur de chaînes rapide
La classe StringBuilder (package java.lang, pas besoin d’importer) est un outil spécialisé pour assembler et modifier efficacement des chaînes. Elle est mutable : on peut ajouter, supprimer, insérer des caractères et des sous-chaînes sans créer un nouvel objet à chaque opération.
Analogie :
Si String est une dalle de béton, alors StringBuilder est un set LEGO : vous ajoutez et retirez des pièces autant que vous voulez sans tout démonter.
Comment créer un StringBuilder
StringBuilder sb = new StringBuilder(); // vide
StringBuilder sb2 = new StringBuilder("Valeur initiale");
Méthodes principales
| Méthode | Description | Exemple d’utilisation |
|---|---|---|
|
Ajouter à la fin une chaîne, un nombre, un caractère, etc. | |
|
Insérer une valeur à la position indiquée | |
|
Supprimer les caractères de start (inclus) à end (exclus) | |
|
Remplacer une partie de la chaîne par un autre contenu | |
|
Inverser la chaîne | |
|
Convertir en chaîne classique | |
|
Raccourcir ou compléter la chaîne à la longueur indiquée | |
Exemple d’utilisation
StringBuilder sb = new StringBuilder();
sb.append("Bonjour, ");
sb.append("monde!");
System.out.println(sb); // Bonjour, monde!
sb.insert(9, "Java "); // inserons "Java " après "Bonjour, "
System.out.println(sb); // Bonjour, Java monde!
sb.replace(9, 13, "autre"); // remplaçons "Java" par "autre"
System.out.println(sb); // Bonjour, autre monde!
sb.reverse();
System.out.println(sb); // !ednom ertua ,ruojnoB
3. StringBuffer : grand frère avec sécurité pour le multithreading
Quelle est la différence entre StringBuilder et StringBuffer ?
- StringBuilder est rapide, mais non thread-safe (non synchronisé).
- StringBuffer est plus lent, mais thread-safe (synchronisé).
Si votre application fonctionne sur un seul thread, utilisez StringBuilder (plus rapide). Si plusieurs threads peuvent modifier la même chaîne, utilisez StringBuffer.
4. Quand utiliser StringBuilder à la place de String ?
Scénarios
- Modifications fréquentes d’une chaîne (ajout, suppression, insertion) dans une boucle ou lors de l’assemblage de gros textes.
- Assemblage d’une chaîne à partir d’un tableau/d’une liste (CSV, HTML, rapports, etc.).
- Analyse et traitement de texte avec un grand nombre d’opérations sur la chaîne.
Exemple : assembler une chaîne à partir d’un tableau
Mauvaise approche (avec String et +) :
String[] names = {"John", "Peter", "Maria"};
String result = "";
for (int i = 0; i < names.length; i++)
{
result += names[i];
if (i < names.length - 1)
{
result += ", ";
}
}
System.out.println(result);
Bonne approche (avec StringBuilder) :
String[] names = {"John", "Peter", "Maria"};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < names.length; i++)
{
sb.append(names[i]);
if (i < names.length - 1)
{
sb.append(", ");
}
}
System.out.println(sb.toString());
Différence : dans le premier cas, une nouvelle chaîne est créée à chaque étape ; dans le second, on étend un seul objet StringBuilder.
5. Comparaison des performances : String vs StringBuilder
// Avec String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " ms");
// Avec StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " ms");
Conclusion : dans la plupart des cas, StringBuilder est de plusieurs ordres de grandeur plus rapide pour des concaténations multiples.
6. Subtilités utiles
Peut-on utiliser les méthodes de String ?
StringBuilder a ses propres méthodes. Pour obtenir une chaîne, appelez toString().
StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString(); // s est maintenant une chaîne ordinaire
Peut-on comparer des StringBuilder avec equals ?
Attention : sb1.equals(sb2) compare les références, pas le contenu. Comparez ainsi :
if (sb1.toString().equals(sb2.toString()))
{
// le contenu est identique
}
Peut-on passer un StringBuilder à System.out.println ?
Oui. System.out.println appellera toString() automatiquement.
Peut-on lire des caractères par indice ?
Oui, utilisez charAt(int index), comme pour une chaîne ordinaire.
7. Erreurs typiques avec StringBuilder et StringBuffer
Erreur n°1 : comparer deux StringBuilder avec equals ou l’opérateur ==. Ces vérifications comparent les références, pas le contenu. Utilisez toString() et la comparaison de chaînes.
Erreur n°2 : oublier d’appeler toString() là où une String est attendue (valeur de retour, journalisation, passage à une API).
Erreur n°3 : utiliser StringBuilder pour deux concaténations simples. Une écriture du type "Hello, " + name est lisible et efficace.
Erreur n°4 : concaténer des String dans une boucle avec +. C’est inefficace en temps et en mémoire — utilisez StringBuilder.
Erreur n°5 : confondre StringBuffer et StringBuilder sans nécessité. S’il n’y a pas de modification concurrente depuis plusieurs threads, choisissez StringBuilder.
Erreur n°6 : tronquer aveuglément le contenu d’un StringBuilder avec setLength(). Vérifiez la validité de la nouvelle longueur : les données au‑delà seront perdues.
GO TO FULL VERSION