StringBuilder vs StringBuffer en Java

1. Vue d'ensemble

Dans ce court article, nous allons examiner les similitudes et les différences entre StringBuilder et StringBuffer en Java.

En termes simples, StringBuilder a été introduit dans Java 1.5 en remplacement de StringBuffer .

2. Similitudes

Les deux StringBuilder et StringBuffer créer des objets qui contiennent une séquence de caractères mutable. Voyons comment cela fonctionne et comment cela se compare à une classe String immuable :

String immutable = "abc"; immutable = immutable + "def";

Même s'il peut sembler que nous modifions le même objet en ajoutant «def» , nous en créons un nouveau car les instances String ne peuvent pas être modifiées.

Lorsque vous utilisez StringBuffer ou StringBuilder, nous pouvons utiliser la méthode append () :

StringBuffer sb = new StringBuffer("abc"); sb.append("def");

Dans ce cas, aucun nouvel objet n'a été créé. Nous avons appelé la méthode append () sur l' instance sb et modifié son contenu. StringBuffer et StringBuilder sont des objets mutables.

3. Différences

StringBuffer est synchronisé et donc thread-safe. StringBuilder est compatible avec l'API StringBuffer mais sans aucune garantie de synchronisation.

Comme il ne s'agit pas d'une implémentation thread-safe, elle est plus rapide et il est recommandé de l'utiliser dans des endroits où la sécurité des threads n'est pas nécessaire.

3.1. Performance

Dans les petites itérations, la différence de performance est insignifiante. Faisons un micro-benchmark rapide avec JMH:

@State(Scope.Benchmark) public static class MyState { int iterations = 1000; String initial = "abc"; String suffix = "def"; } @Benchmark public StringBuffer benchmarkStringBuffer(MyState state) { StringBuffer stringBuffer = new StringBuffer(state.initial); for (int i = 0; i < state.iterations; i++) { stringBuffer.append(state.suffix); } return stringBuffer; } @Benchmark public StringBuilder benchmarkStringBuilder(MyState state) { StringBuilder stringBuilder = new StringBuilder(state.initial); for (int i = 0; i < state.iterations; i++) { stringBuilder.append(state.suffix); } return stringBuilder; }

Nous avons utilisé le mode Débit par défaut - c'est-à-dire des opérations par unité de temps (un score plus élevé est meilleur), ce qui donne:

Benchmark Mode Cnt Score Error Units StringBufferStringBuilder.benchmarkStringBuffer thrpt 200 86169.834 ± 972.477 ops/s StringBufferStringBuilder.benchmarkStringBuilder thrpt 200 91076.952 ± 2818.028 ops/s

Si nous augmentons le nombre d'itérations de 1k à 1m, nous obtenons:

Benchmark Mode Cnt Score Error Units StringBufferStringBuilder.benchmarkStringBuffer thrpt 200 77.178 ± 0.898 ops/s StringBufferStringBuilder.benchmarkStringBuilder thrpt 200 85.769 ± 1.966 ops/s

Cependant, gardons à l'esprit qu'il s'agit d'un micro-benchmark, qui peut ou non avoir un impact réel sur les performances réelles et réelles d'une application.

4. Conclusions

En termes simples, StringBuffer est une implémentation thread-safe et donc plus lente que StringBuilder .

Dans les programmes à un seul thread, nous pouvons prendre du StringBuilder . Pourtant, le gain de performances de StringBuilder par rapport à StringBuffer peut être trop faible pour justifier son remplacement partout. C'est toujours une bonne idée de profiler l'application et de comprendre ses caractéristiques de performances d'exécution avant d'effectuer tout type de travail pour remplacer une implémentation par une autre.

Enfin, comme toujours, le code utilisé lors de la discussion se trouve à l'adresse over sur GitHub.