StringBuilder и StringBuffer в Java
1. обзор
В этой короткой статье мы рассмотрим сходства и различия междуStringBuilder иStringBuffer в Java.
Проще говоря,StringBuilder был введен в Java 1.5 как заменаStringBuffer.
2. сходства
ИStringBuilder, иStringBuffer создают объекты, содержащиеa mutable sequence of characters. Давайте посмотрим, как это работает и в сравнении с неизменным классомString:
String immutable = "abc";
immutable = immutable + "def";
Хотя может показаться, что мы изменяем тот же объект, добавляя“def”, мы создаем новый, потому что экземплярыString не могут быть изменены.
При использованииStringBuffer илиStringBuilder, мы можем использовать методappend():
StringBuffer sb = new StringBuffer("abc");
sb.append("def");
В этом случае новый объект не был создан. Мы вызвали методappend() для экземпляраsb и изменили его содержимое. StringBuffer иStringBuilder - изменяемые объекты.
3. Различия
StringBuffer синхронизирован и, следовательно, безопасен для потоков. StringBuilder совместим с APIStringBuffer, но без гарантии синхронизации.
Поскольку это не потокобезопасная реализация, она работает быстрее, и ее рекомендуется использовать там, где нет необходимости в безопасности потоков.
3.1. Спектакль
В маленьких итерациях разница в производительности незначительна. Давайте проведем быстрый микро-тест с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;
}
Мы использовали режимThroughput по умолчанию, т.е. операций за единицу времени (чем выше оценка, тем лучше), что дает:
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
Если мы увеличим количество итераций с 1к до 1м, то получим:
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
Однако давайте иметь в виду, что это микротест, который может или не может реально повлиять на реальную, реальную производительность приложения.
4. Выводы
Проще говоря,StringBuffer является поточно-ориентированной реализацией и поэтому медленнее, чемStringBuilder.
В однопоточных программах мы можем взятьStringBuilder. Тем не менее,the performance gain of StringBuilder over StringBuffer may be too small to justify replacing it everywhere. Всегда полезно профилировать приложение и понимать его характеристики производительности во время выполнения, прежде чем выполнять какую-либо работу по замене одной реализации другой.
Наконец, как всегда, код, использованный во время обсуждения, можно найтиover on GitHub.