Чому StringBuilder, коли існує String?


83

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

Чому другий Stringклас?

Де я можу дізнатись більше StringBuilder?



Я просто хотів зазначити, що це насправді одного разу постало для мене як питання інтерв'ю. Вони запитали, що я хотів би заповнити великий рядок .....
preOtep

Відповіді:


172

Stringне дозволяє додавати. Кожен метод, який ви викликаєте в a, Stringстворює новий об'єкт і повертає його. Це тому, що Stringє незмінним - він не може змінити свій внутрішній стан.

З іншого боку StringBuilderє змінним. Коли ви викликаєте append(..)це змінює внутрішній масив char, а не створює новий об'єкт рядка.

Таким чином, ефективніше мати:

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

а не str += i, що створить 500 нових рядкових об'єктів.

Зверніть увагу, що у прикладі я використовую цикл. Як зазначає helios у коментарях, компілятор автоматично перекладає вирази like 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 (), щоб уникнути продуктивності створення об'єкта штрафні санкції ":)
Геліос

і всі дякую. Ви всі заслуговуєте
оцінок

супер, як відкликання "незмінних" об'єктів.
Gary Tsui

Чудові відгуки. Проте я сумую за тим, що ми не можемо просто так, щоб компілятор зрозумів, коли просто використовувати Stringbuilder більшу частину часу , включаючи цикли for, так що вам не потрібно думати про це як про розробника. :)
worldsayshi 02

Хороша відповідь . Я хотів би додати такі рядки: Рядок незмінний, оскільки масив (тобто значення char []), що містить рядок, оголошується остаточним, але у випадку StringBuilder масив (тобто значення char []), який містить рядок, не є остаточним. Ви можете вносити зміни в масив, що містить рядок, у випадку Stringbuilder
Deen John

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

Як бачите, різниця в продуктивності значна.


Ps. Я запустив це на своєму ядрі Macbook Pro Dual.
Амір Рамінфар

25
Це пояснює, чому StringBuilder, коли існує String? Це не пояснює, чому StringBuilder так швидкий. але це не Питання. Тож це вірна відповідь.
Kerem Baydoğan

2
@krmby - Погоджено. Відповісти, чому насправді, призначено для іншого питання.
Амір Рамінфар

12
Я думаю, щоб зробити порівняння справедливим, ви повинні включити час для виконання a s = sb.ToString();в кінці, щоб принаймні ви зробили те саме в обох прикладах (результат a string).
Скотт Уітлок,

19

Клас рядка є незмінним, тоді як StringBuilder є змінним.

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

Наведений вище код створить два об’єкти, оскільки рядок є незмінним

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

Наведений вище код створить лише один об'єкт, оскільки StringBuilder не є незмінним.

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


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.

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. У такому випадку він не буде зібраний шляхом повторного виділення рядків.
scottb

1

Java має String, StringBuffer і StringBuilder:

  • Рядок: Його незмінна

  • StringBuffer: його змінні та безпечні потоки

  • 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);
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.