Ответы:
Разница изменчивости:
String
является неизменным , если вы пытаетесь изменить их значения, создается другой объект, тогда как StringBuffer
и StringBuilder
являются изменяемыми, чтобы они могли изменять свои значения.
Разница в безопасности потоков:
Разница между StringBuffer
и в StringBuilder
том, что StringBuffer
потокобезопасен. Поэтому, когда приложение необходимо запустить только в одном потоке, его лучше использовать StringBuilder
. StringBuilder
более эффективен, чем StringBuffer
.
Ситуации:
String
объект неизменен.StringBuilder
.StringBuffer
потому что StringBuffer
является синхронным, чтобы обеспечить безопасность потоков.Strings
когда мы изменяем значение, создается другой объект. Обнуляется ли старая ссылка на объект, чтобы она могла быть собрана сборщиком мусора GC
или даже сборщиком мусора?
String
с StringBuilder
?
String
когда неизменяемая структура подходит; получение новой символьной последовательности из String
может привести к неприемлемому снижению производительности, как во время ЦП, так и в памяти (получение подстрок эффективно при использовании ЦП, поскольку данные не копируются, но это означает, что потенциально гораздо больший объем данных может остаться выделенным).StringBuilder
когда вам нужно создать изменяемую последовательность символов, обычно для объединения нескольких последовательностей символов вместе.StringBuffer
в тех же условиях, что и при использовании StringBuilder
, но когда изменения в базовой строке должны быть синхронизированы (потому что несколько потоков читают / модифицируют строковый буфер).Смотрите пример здесь .
Основы:
String
это неизменный класс, его нельзя изменить.
StringBuilder
является изменяемым классом, который можно добавлять, заменять или удалять символы и в конечном итоге преобразовывать String
StringBuffer
в исходную синхронизированную версиюStringBuilder
Вы должны предпочитать StringBuilder
во всех случаях, когда у вас есть только один поток доступа к вашему объекту.
Детали:
Также обратите внимание, что StringBuilder/Buffers
это не магия, они просто используют Array в качестве вспомогательного объекта и что Array необходимо перераспределять, когда он заполнен. Будьте уверены, и создавайте ваши StringBuilder/Buffer
объекты достаточно большими, чтобы их не приходилось постоянно менять каждый раз при .append()
вызове.
Изменение размеров может стать очень вырожденным. Он в основном изменяет размеры резервного массива в 2 раза по сравнению с его текущим размером каждый раз, когда его необходимо расширить. Это может привести к тому, что большие объемы ОЗУ выделяются и не используются, когда StringBuilder/Buffer
классы начинают расти.
В Java String x = "A" + "B";
используется StringBuilder
негласно. Так что для простых случаев нет смысла декларировать свое собственное. Но если вы создаете String
объекты большого размера, скажем, менее 4 КБ, тогда объявление StringBuilder sb = StringBuilder(4096);
намного эффективнее, чем конкатенация или использование конструктора по умолчанию, который состоит всего из 16 символов. Если у вас String
будет меньше 10 КБ, инициализируйте его конструктором до 10 КБ, чтобы быть в безопасности. Но если он инициализируется до 10 КБ, то вы записываете на 1 символ больше 10 КБ, он будет перераспределен и скопирован в массив из 20 КБ. Так что инициализация высокого лучше, чем низкого.
В случае автоматического изменения размера, у 17-го символа резервный массив перераспределяется и копируется в 32 символа, у 33-го это происходит снова, и вы перераспределяете и копируете массив в 64 символа. Вы можете видеть, как это вырождается во многих перераспределениях и копиях, и это то, что вы действительно стараетесь избегать StringBuilder/Buffer
в первую очередь.
Это из исходного кода JDK 6 для AbstractStringBuilder
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
Лучшая практика - инициализировать StringBuilder/Buffer
немного больше, чем вам нужно, если вы не знаете сразу, насколько велик String
будет, но вы можете догадаться. Одно выделение чуть больше памяти, чем вам нужно, будет лучше, чем много перераспределений и копий.
Также остерегайтесь инициализации StringBuilder/Buffer
с помощью String
символа as, который будет выделять только размер строки String + 16, что в большинстве случаев просто начнет вырожденный цикл перераспределения и копирования, которого вы пытаетесь избежать. Следующее прямо из исходного кода Java 6.
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
Если вы случайно столкнулись с экземпляром, StringBuilder/Buffer
который вы не создали и не можете контролировать вызываемый конструктор, есть способ избежать вырожденного поведения перераспределения и копирования. Позвоните .ensureCapacity()
с размером, который вы хотите, чтобы ваш результат String
соответствовал.
Альтернативы:
В качестве примечания, если вы делаете действительно тяжелое String
построение и манипулирование, есть гораздо более ориентированная на производительность альтернатива, называемая Веревками .
Другой альтернативой является создание StringList
реализации путем подкласса ArrayList<String>
и добавления счетчиков для отслеживания количества символов в каждой .append()
и других операциях мутации в списке, а затем переопределения .toString()
для создания StringBuilder
нужного вам размера, циклического перемещения по списку и построения. вывод, вы даже можете сделать StringBuilder
это экземпляром переменной и «кэшировать» результаты, .toString()
и вам нужно будет только сгенерировать его, когда что-то изменится.
Также не забывайте о String.format()
создании фиксированного форматированного вывода, который может быть оптимизирован компилятором, так как он делает его лучше.
String x = "A" + "B";
Действительно ли компилируется, чтобы быть StringBuilder? Почему бы просто не скомпилировать String x = "AB";
, он должен использовать только StringBuilder, если компоненты не известны во время компиляции.
Вы имеете в виду, для объединения?
Пример из реального мира: вы хотите создать новую строку из множества других .
Например, чтобы отправить сообщение:
строка
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
Или
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer (синтаксис такой же, как и у StringBuilder, эффекты отличаются)
Около
StringBuffer
против StringBuilder
Первый синхронизирован, а позже нет.
Таким образом, если вы вызываете его несколько раз в одном потоке (что составляет 90% случаев), он StringBuilder
будет работать намного быстрее, потому что не остановится, чтобы увидеть, владеет ли он блокировкой потока.
Таким образом, рекомендуется использовать StringBuilder
(если, конечно, у вас есть несколько потоков, обращающихся к нему одновременно, что редко)
String
конкатенация ( с использованием оператора + ) может быть оптимизирована компилятором для использования StringBuilder
под ней, так что больше не о чем беспокоиться, в древние времена Java это было то, о чем все говорят, что следует избегать любой ценой, потому что каждая конкатенация создал новый объект String. Современные компиляторы больше этого не делают, но все же рекомендуется использовать их на StringBuilder
всякий случай, если вы используете «старый» компилятор.
редактировать
Просто для того, кому интересно, вот что делает компилятор для этого класса:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
Строки с номерами 5 - 27 предназначены для строки с именем «literal».
Строки с номерами 31-53 предназначены для строки с именем «строитель»
Разницы нет, для обеих строк выполняется одинаковый код.
StringBuilder
конкатенацию для выполнения строк в правой части назначения. Любая хорошая реализация будет использовать StringBuilder за кулисами, как вы говорите. Кроме того, ваш пример "a" + "b"
будет скомпилирован в один литерал, "ab"
но если вы StringBuilder
его используете, это приведет к двум ненужным вызовам append()
.
"a"+"b"
но чтобы сказать, что такое конкатенация строк, я изменил ее на явный. То, что вы не говорите, это то, почему не стоит делать это. Это именно то, что делает (современный) компилятор. @ fuzzy, я согласен, особенно если вы знаете, какой будет размер последней строки (aprox).
-------------------------------------------------- -------------------------------- String StringBuffer StringBuilder -------------------------------------------------- -------------------------------- Складское помещение | Постоянная куча кучи пула Модифицируемый | Нет (неизменяемый) Да (изменяемый) Да (изменяемый) Поток Безопасный | Да да нет Производительность | Быстро очень медленно быстро -------------------------------------------------- --------------------------------
synchronised
и вот почему .
строка
String class
Представляет собой строку символов. Все строковые литералы в Java-программе, например "abc"
, реализованы как экземпляры этого класса.
Строковые объекты неизменны, как только они созданы, мы не можем их изменить. ( Строки являются постоянными )
Если строка создается с помощью конструктора или метода , то эти строки будут храниться в динамической памяти , а также SringConstantPool
. Но перед сохранением в пуле он вызывает intern()
метод проверки доступности объекта с тем же содержимым в пуле, используя метод equals. Если в пуле имеется String-copy, возвращается ссылка. В противном случае объект String добавляется в пул и возвращает ссылку.
+
) и для преобразования других объектов в строки. Конкатенация строк реализуется через класс StringBuilder (или StringBuffer) и его метод добавления.String heapSCP = new String("Yash");
heapSCP.concat(".");
heapSCP = heapSCP + "M";
heapSCP = heapSCP + 777;
// For Example: String Source Code
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
Строковые литералы хранятся в StringConstantPool
.
String onlyPool = "Yash";
StringBuilder и StringBuffer являются изменяемой последовательностью символов. Это означает, что можно изменить значение этих объектов. StringBuffer имеет те же методы, что и StringBuilder, но каждый метод в StringBuffer синхронизирован, поэтому он безопасен для потоков.
Данные StringBuffer и StringBuilder могут быть созданы только с использованием оператора new. Таким образом, они сохраняются в памяти кучи.
Экземпляры StringBuilder не безопасны для использования несколькими потоками. Если такая синхронизация требуется, то рекомендуется использовать StringBuffer.
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer и StringBuilder оказывают специальные методы , такие как.,
replace(int start, int end, String str)
И reverse()
.
ПРИМЕЧАНИЕ : StringBuffer и SringBuilder являются изменяемыми, поскольку они обеспечивают реализацию
Appendable Interface
.
Когда использовать какой.
Если вы не собираетесь менять значение каждый раз, то лучше использовать String Class
. Как часть Обобщений, если вы хотите Сортировать Comparable<T>
или сравнить значения, тогда переходите к String Class
.
//ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add( threadSafe );
System.out.println("Set : "+ set);
Если вы собираетесь каждый раз изменять значение, используйте StringBuilder, который работает быстрее, чем StringBuffer. Если несколько потоков изменяют значение, переходите к StringBuffer.
Кроме того, StringBuffer
потокобезопасен, что StringBuilder
не так.
Так что в ситуации реального времени, когда разные потоки обращаются к нему, StringBuilder
может иметь неопределенный результат.
Обратите внимание, что если вы используете Java 5 или новее, вы должны использовать StringBuilder
вместо StringBuffer
. Из документации API:
Начиная с выпуска JDK 5 этот класс был дополнен эквивалентным классом, предназначенным для использования одним потоком
StringBuilder
. ЭтотStringBuilder
класс, как правило, следует использовать предпочтительнее этого, поскольку он поддерживает все те же операции, но он быстрее, поскольку не выполняет синхронизацию.
На практике вы почти никогда не будете использовать это из нескольких потоков одновременно, поэтому синхронизация StringBuffer
почти всегда не требует ненужных затрат.
Лично я не думаю, что есть реальная польза для этого StringBuffer
. Когда я захочу общаться между несколькими потоками, манипулируя последовательностью символов? Звучит совсем не полезно, но, может быть, мне еще предстоит увидеть свет :)
Разница между String и двумя другими классами заключается в том, что String является неизменным, а два других являются изменяемыми классами.
Но почему у нас есть два класса для одной цели?
Причина в том, что StringBuffer
является потокобезопасным и StringBuilder
не является.
StringBuilder
Это новый класс, StringBuffer Api
который был введен JDK5
и всегда рекомендуется, если вы работаете в однопоточной среде, так какFaster
Для получения полной информации вы можете прочитать http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
В Java String является неизменным. Будучи неизменными, мы имеем в виду, что после создания строки мы не можем изменить ее значение. StringBuffer является изменяемым. После создания объекта StringBuffer мы просто добавляем содержимое к значению объекта, а не создаем новый объект. StringBuilder похож на StringBuffer, но он не является потокобезопасным. Методы StingBuilder не синхронизированы, но по сравнению с другими строками Stringbuilder работает быстрее всего. Вы можете узнать разницу между String, StringBuilder и StringBuffer , реализовав их.