String, StringBuffer и StringBuilder

Скажите, пожалуйста, в реальном времени сравнить String, StringBuffer и StringBuilder?

Ответ 1

Разность взаимозаменяемости:

String неизменный, если вы пытаетесь изменить их значения, создается другой объект, тогда как StringBuffer и StringBuilder являются изменчивыми, поэтому они могут изменять их значения.

Разница потоков:

Разница между StringBuffer и StringBuilder заключается в том, что StringBuffer является потокобезопасным. Поэтому, когда приложение нужно запускать только в одном потоке, лучше использовать StringBuilder. StringBuilder более эффективен, чем StringBuffer.

Ситуации:

  • Если ваша строка не изменится, используйте класс String, потому что объект String является неизменным.
  • Если ваша строка может измениться (например: много логики и операций в построении строки) и будет доступен только из одного потока, использование StringBuilder будет достаточно хорошим.
  • Если ваша строка может измениться и будет доступна из нескольких потоков, используйте StringBuffer, потому что StringBuffer является синхронным, поэтому вы обеспечиваете безопасность потоков.

Ответ 2

  • Вы используете String, когда необходима неизменяемая структура; получение новой последовательности символов из String может приводить к неприемлемому снижению производительности либо в процессорном времени, либо в памяти (получение подстрок является эффективным ЦП, поскольку данные не копируются, но это означает, что потенциально гораздо больший объем данных может оставаться выделенным).
  • Вы используете StringBuilder, когда вам нужно создать изменяемую последовательность символов, как правило, чтобы объединить несколько последовательностей символов вместе.
  • Вы используете StringBuffer в тех же обстоятельствах, что использовали бы StringBuilder, но когда изменения в базовой строке должны быть синхронизированы (потому что несколько потоков читают/изменяют строковый буфер).

См. пример здесь.

Ответ 3

Основы:

String является неизменным классом, его нельзя изменить. StringBuilder - это изменяемый класс, который может быть добавлен, заменены или удалены символы и в конечном итоге преобразованы в String StringBuffer - это исходная синхронизированная версия StringBuilder

Вы должны предпочесть StringBuilder во всех случаях, когда у вас есть только один поток, обращающийся к вашему объекту.

Детали:

Также обратите внимание, что StringBuilder/Buffers не являются волшебными, они просто используют Array в качестве объекта поддержки и что Array необходимо перераспределить, когда он заполняется. Будьте уверены, и создайте свои объекты StringBuilder/Buffer достаточно крупными изначально, где им не нужно постоянно изменять размер каждый раз, когда вызывается .append().

Повторная калибровка может стать очень вырожденной. Он в основном изменяет размер массива поддержки в 2 раза по сравнению с его текущим размером каждый раз, когда его нужно расширить. Это может привести к тому, что большие объемы ОЗУ будут выделены и не будут использоваться, когда классы StringBuilder/Buffer начнут расти.

В Java String x = "A" + "B"; используется StringBuilder за кулисами. Таким образом, для простых случаев нет никакой пользы от объявления вашего. Но если вы строите большие объекты String, скажем, менее 4k, то объявление StringBuilder sb = StringBuilder(4096); намного эффективнее, чем конкатенация, или используя конструктор default, который составляет всего 16 символов. Если ваш String будет меньше 10k, тогда инициализируйте его с конструктором до 10k, чтобы быть в безопасности. Но если он инициализируется до 10k, тогда вы пишете 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, поскольку для этого будет выделен только размер String + 16 символов, который в большинстве случаев просто запустит процесс вырожденного повторного выделения и копирования, который вы пытаетесь избежать. Ниже приведен исходный код Java.

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

Если вы случайно закончите с экземпляром StringBuilder/Buffer, который вы не создали и не можете управлять вызываемым конструктором, существует способ избежать вырожденного перераспределения и копирования. Вызовите .ensureCapacity() с размером, который вы хотите, чтобы ваш итоговый String вписывался в.

Альтернативы:

Как примечание, если вы делаете действительно тяжелое String создание и манипулирование, существует гораздо более ориентированная на производительность альтернатива, называемая Ropes.

Другой альтернативой является создание реализации StringList путем подклассификации ArrayList<String> и добавление счетчиков для отслеживания количества символов для каждой операции .append() и других мутаций в списке, а затем переопределить .toString() на создайте StringBuilder точного размера, который вам нужен, и прокрутите список и создайте вывод, вы даже можете сделать эту переменную StringBuilder переменной экземпляра и "кешем" результаты .toString() и только ее нужно повторно сгенерировать когда что-то меняется.

Также не забывайте о String.format() при создании файла с фиксированным форматированием, который может быть оптимизирован компилятором по мере их улучшения.

Ответ 4

Вы имеете в виду, для конкатенации?

Пример реального мира: вы хотите создать новую строку из многих других.

Например, чтобы отправить сообщение:

Строка

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 vs. 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 предназначены для строки с именем "строитель"

Нет никакой разницы, именно тот же тот же код выполняется для обеих строк.

Ответ 5

Кроме того, StringBuffer является потокобезопасным, а StringBuilder - нет.

Поэтому в ситуации реального времени, когда к нему обращаются разные потоки, StringBuilder может иметь неопределенный результат.

Ответ 6

Обратите внимание, что если вы используете Java 5 или новее, вы должны использовать StringBuilder вместо StringBuffer. Из документации API:

С момента выпуска JDK 5 этот класс был дополнен эквивалентным классом, предназначенным для использования одним потоком, StringBuilder. Класс StringBuilder обычно должен использоваться в предпочтении этому, поскольку он поддерживает все те же операции, но быстрее, поскольку он не выполняет синхронизацию.

На практике вы почти никогда не будете использовать это из нескольких потоков одновременно, поэтому синхронизация, выполняемая StringBuffer, почти всегда является ненужной служебной информацией.

Ответ 7

Разница между 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/

Ответ 8

----------------------------------------------------------------------------------
                  String                    StringBuffer         StringBuilder
----------------------------------------------------------------------------------                 
Storage Area | Constant String Pool         Heap                   Heap 
Modifiable   |  No (immutable)              Yes( mutable )         Yes( mutable )
Thread Safe  |      Yes                     Yes                     No
 Performance |     Fast                 Very slow                  Fast
----------------------------------------------------------------------------------

Ответ 9

Лично я не думаю, что для StringBuffer существует реальное использование в мире. Когда я когда-нибудь захочу общаться между несколькими потоками, манипулируя символьной последовательностью? Это совсем не полезно, но, возможно, мне еще нужно увидеть свет:)

Ответ 10

В java Строка является неизменной. Будучи неизменными, мы подразумеваем, что после создания String мы не можем изменить его значение. StringBuffer изменен. Когда объект StringBuffer создается, мы просто добавляем контент к значению объекта вместо создания нового объекта. StringBuilder похож на StringBuffer, но он не является потокобезопасным. Методы StingBuilder не синхронизированы, но по сравнению с другими строками, Stringbuilder работает быстрее всего. Вы можете узнать разницу между String, StringBuilder и StringBuffer путем их реализации.

Ответ 11

Семейство строк

Строка

String class представляет символьные строки. Все строковые литералы в программе Java, такие как "abc", реализуются как экземпляры этого класса.

Строковые объекты неизменяемы после их создания мы не можем изменить. (Строки являются константами)

  • Если String создается с использованием конструктора или метода, эти строки будут храниться в Память кучи, а также SringConstantPool. Но перед сохранением в пуле он вызывает метод intern() для проверки доступности объекта с тем же содержимым в пуле с использованием метода equals. Если String-copy доступен в пуле, то возвращается ссылка. В противном случае объект String добавляется в пул и возвращает ссылку.

    • Язык Java обеспечивает специальную поддержку оператора конкатенации строк (+) и для преобразования других объектов в строки. Конкатенация строк реализуется через класс 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 могут создаваться только с использованием нового оператора. Таким образом, они сохраняются в памяти кучи.

  • Экземпляры 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. Как часть Generics, если вы хотите Сортировка 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.