Почему StringBuilder, когда есть String?

83

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

Почему второй Stringкласс?

Где я могу узнать больше StringBuilder?

an00b
источник
Я просто хотел отметить, что однажды этот вопрос возник для меня как вопрос интервью. Они спросили, что бы я сделал, чтобы заполнить большую строку .....
preOtep

Ответы:

172

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

С другой стороны StringBuilder, изменчив. Когда ты звонишьappend(..) он изменяет внутренний массив символов, а не создает новый строковый объект.

Таким образом, эффективнее иметь:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i ++) {
    sb.append(i);
}

а не str += i, что создаст 500 новых строковых объектов.

Обратите внимание, что в примере я использую цикл. Как отмечает helios в комментариях, компилятор автоматически переводит выражения вроде String d = a + b + cна что-то вроде

String d = new StringBuilder(a).append(b).append(c).toString();

Также обратите внимание, что есть StringBufferв дополнение к StringBuilder. Разница в том, что у первого есть синхронизированные методы. Если вы используете его как локальную переменную, используйте StringBuilder. Если случается так, что к нему могут обращаться несколько потоков, используйте StringBuffer(что реже)

Божо
источник
26
+1. Вы можете добавить: «Следовательно, StrungBuilder ищет производительность» и «Компиляторы Java заменяют выражения типа A + B + C новым StringBuilder (A) .append (B) .append (C) .toString (), чтобы избежать производительности при создании объекта. пенальти »:)
helios
и всем большое спасибо. Вы все заслуживаете +1 (которые будут доставлены в кратчайшие сроки :)
an00b
супер как отзыв «неизменяемых» объектов.
Гэри Цуй
Отличные отзывы. Однако мне не хватает того, почему мы не можем просто заставить компилятор выяснять, когда использовать Stringbuilder большую часть времени , в том числе в циклах for, чтобы вам не приходилось думать об этом как о разработчике. :)
worldsayshi 02
Хороший ответ. Я хотел бы добавить эти строки: String неизменяем, поскольку массив (т.е. значение char []), содержащий строку, объявлен окончательным, но в случае StringBuilder массив (т.е. значение char []), содержащий строку, не является окончательным. Вы можете внести изменения в массив, содержащий строку, в случае Stringbuilder
Дин Джон
61

Вот конкретный пример того, почему -

int total = 50000;
String s = ""; 
for (int i = 0; i < total; i++) { s += String.valueOf(i); } 
// 4828ms

StringBuilder sb = new StringBuilder(); 
for (int i = 0; i < total; i++) { sb.append(String.valueOf(i)); } 
// 4ms

Как видите, разница в производительности существенная.

Амир Раминфар
источник
Пс. Я запускал это на своем Macbook Pro Dual core.
Амир Раминфар 08
25
Это объясняет, почему StringBuilder, когда есть String? Это не объясняет, почему StringBuilder такой быстрый. но вопрос не в этом. Так что это правильный ответ.
Керем Байдоган
2
@krmby - Согласен. Ответить почему на самом деле предназначено для другого вопроса.
Амир Раминфар
12
Я думаю, чтобы сравнение было справедливым, вы должны включить время для выполнения s = sb.ToString();в конце, чтобы, по крайней мере, вы сделали то же самое в обоих примерах (результат - a string).
Скотт Уитлок,
19

Класс String неизменен, тогда как StringBuilder изменчив.

String s = "Hello";
s = s + "World";

Приведенный выше код создаст два объекта, потому что String неизменяем

StringBuilder sb = new StringBuilder("Hello");
sb.append("World");

Приведенный выше код создаст только один объект, потому что StringBuilder не является неизменным.

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

unk1102
источник
8

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

Рекс М
источник
5

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

Самая большая проблема со String заключается в том, что любая операция, которую вы выполняете с ним, всегда будет возвращать новый объект, например:

String s1 = "something";
String s2 = "else";
String s3 = s1 + s2; // this is creating a new object.
CarlosZ
источник
4

StringBuilder хорош, когда вы имеете дело с большими строками. Это поможет вам повысить производительность.

Вот статья, которая оказалась мне полезной.

Вам мог бы помочь быстрый поиск в Google. Теперь вы наняли 7 разных людей, чтобы они выполняли поиск в Google. :)

Ванчинатан Чандрасекаран
источник
Разве мы все не делаем здесь неоплачиваемую работу?
CA Arefe
4

Чтобы быть точным, StringBuilder, добавляющий все строки, равен O (N), а добавление String - O (N ^ 2). Проверяя исходный код, внутренне это достигается за счет хранения изменяемого массива символов. StringBuilder использует метод дублирования длины массива для достижения амортизированной производительности O (N ^ 2) за счет возможного удвоения требуемой памяти. Для решения этой проблемы в конце можно вызвать trimToSize, но обычно объекты StringBuilder используются только временно. Вы можете еще больше повысить производительность, предоставив хорошее начальное предположение о конечном размере строки.

красное дерево
источник
3

Эффективность.

Каждый раз, когда вы объединяете строки, будет создаваться новая строка. Например:

String out = "a" + "b" + "c";

Это создает новую временную строку, копирует в нее «a» и «b», в результате получается «ab». Затем он создает другую новую временную строку, копирует в нее «ab» и «c», в результате получается «abc». Затем этот результат присваиваетсяout .

Результатом является алгоритм Шлемиля Художника с квадратичной временной сложностью O (n²).

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

Томас
источник
Многие реализации JVM скомпилируют ваш пример в StringBuilder, а затем преобразуют конечный результат в String. В таком случае он не будет собираться путем повторного выделения String.
Скотт
1

В Java есть String, StringBuffer и StringBuilder:

  • Строка: его неизменяемый

  • StringBuffer: его изменяемый и ThreadSafe

  • StringBuilder: его изменяемый, но не ThreadSafe, представленный в Java 1.5

Строка, например:

public class T1 {

    public static void main(String[] args){

        String s = "Hello";

        for (int i=0;i<10;i++) {

            s = s+"a";
            System.out.println(s);
        }
    }
}

}

вывод: будет создано 10 различных строк вместо 1 строки.

Helloa
Helloaa
Helloaaa
Helloaaaa
Helloaaaaa
Helloaaaaaa
Helloaaaaaaa
Helloaaaaaaaa 
Helloaaaaaaaaa 
Helloaaaaaaaaaa

StringBuilder например: будет создан только 1 объект StringBuilder.

public class T1 {

    public static void main(String[] args){

        StringBuilder s = new StringBuilder("Hello");

        for (int i=0;i<10;i++) {    
            s.append("a");
            System.out.println(s);
        }
    }
}
Кумар Вивек Митра
источник