StringBuilder vs StringBuffer : les 10 différences clés en Java

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

StringBuilder vs StringBuffer : que choisir et pourquoi est-ce important ?

\n\n

Si vous avez déjà écrit du code Java qui manipule intensivement des chaînes de caractères (par exemple, pour construire une requête SQL, générer du JSON ou simplement concaténer des dizaines de fragments de texte), vous avez sûrement été confronté au dilemme : StringBuilder ou StringBuffer ? Sur Stack Overflow, cette question cumule des centaines de milliers de vues, et ce n'est pas un hasard. À première vue, ces classes sont comme des jumeaux : elles étendent toutes deux AbstractStringBuilder, utilisent un tableau de caractères modifiable, et proposent les méthodes append(), insert(), delete(). Mais le diable se cache dans les détails, comme toujours.

\n\n

Dans cet article, nous ne nous contenterons pas d'énumérer les différences. Nous les analyserons avec des exemples concrets, explorerons les coulisses de la JVM et répondrons aux questions que l'on vous posera inévitablement en entretien. C'est parti !

\n\n

1. La différence principale : la synchronisation

\n\n

C'est le point le plus important, la raison d'être de toute cette histoire. StringBuffer est thread-safe (sécurisé pour les threads). La quasi-totalité de ses méthodes publiques sont synchronisées avec le mot-clé synchronized. StringBuilder, en revanche, n'est pas synchronisé. Point final.

\n\n

Regardons le code (version simplifiée du JDK réel) :

\n\n
// StringBuffer (Java 17)\npublic synchronized StringBuffer append(String str) {\n    toStringCache = null;\n    super.append(str);\n    return this;\n}\n\n// StringBuilder\npublic StringBuilder append(String str) {\n    super.append(str);\n    return this;\n}\n
\n\n

Une seule ligne synchronized fait toute la différence. Mais cette ligne change tout : les performances, le domaine d'application, et même l'architecture de votre application.

\n\n

Quand utiliser StringBuffer ?

\n
    \n
  • Vous développez une application multithread.
  • \n
  • La même instance de StringBuffer est utilisée par plusieurs threads sans synchronisation externe.
  • \n
  • Exemple : un logger qui collecte des messages provenant de différents threads dans un seul buffer.
  • \n
\n\n

Quand utiliser StringBuilder ?

\n
    \n
  • Code monothread (90 % des cas).
  • \n
  • Variables locales à l'intérieur d'une méthode.
  • \n
  • Boucles avec concaténation de chaînes (le compilateur vous suggérera lui-même StringBuilder).
  • \n
\n\n

2. Performances : qui est le plus rapide ?

\n\n

Ici, rien de surprenant : StringBuilder est plus rapide que StringBuffer. De combien ? Cela dépend de la charge, mais en moyenne de 2 à 5 fois. Vérifions cela avec un simple benchmark.

\n\n
public class PerformanceTest {\n    private static final int ITERATIONS = 10_000_000;\n\n    public static void main(String[] args) {\n        // StringBuilder\n        long start = System.nanoTime();\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < ITERATIONS; i++) {\n            sb.append("a");\n        }\n        long sbTime = System.nanoTime() - start;\n\n        // StringBuffer\n        start = System.nanoTime();\n        StringBuffer sbf = new StringBuffer();\n        for (int i = 0; i < ITERATIONS; i++) {\n            sbf.append("a");\n        }\n        long sbfTime = System.nanoTime() - start;\n\n        System.out.println("StringBuilder : " + sbTime / 1_000_000 + " ms");\n        System.out.println("StringBuffer  : " + sbfTime / 1_000_000 + " ms");\n        System.out.println("StringBuffer est " + (sbfTime / (double) sbTime) + " fois plus lent");\n    }\n}\n
\n\n

Sur mon ordinateur portable (Intel i7, 16 Go de RAM, Java 17), le résultat est constant : StringBuilder ~180 ms, StringBuffer ~620 ms. La différence est de près de 3,5 fois. Et si l'on ajoute du travail réel (analyse, formatage), l'écart peut encore se creuser. Pourquoi ? Parce que chaque appel à synchronized implique une vérification du moniteur, une acquisition de verrou et sa libération. Dans un code monothread, c'est une pure perte de temps.

\n\n
\n Important : Si votre méthode garantit

Blogs

Book Recommendations