JavaRush /Курси /JAVA 25 SELF /StringBuilder і StringBuffer

StringBuilder і StringBuffer

JAVA 25 SELF
Рівень 9 , Лекція 5
Відкрита

1. Незмінність рядка: друг чи ворог?

У Java клас Stringнезмінний (immutable). Це означає, що після створення рядок не можна змінити. Щоразу, коли ви «змінюєте» рядок, наприклад, додаєте до нього щось через + або concat(), насправді створюється новий обʼєкт, а старий вирушає на звалище (поки його не прибере збирач сміття).

Приклад:

String s = "Привіт";
s = s + " світ!";
System.out.println(s); // Привіт світ!

Здається, що рядок s змінився, але насправді створився новий рядок "Привіт світ!", а старий "Привіт" залишився в памʼяті, доки його не прибере збирач сміття. Якщо таких операцій багато — наприклад, у циклі, — програма сповільнюється і споживає зайву памʼять.

Уявіть, що ви будуєте вежу з кубиків і щоразу, коли хочете додати новий кубик, доводиться перебудовувати всю вежу заново. Не дуже економно, правда? Так само поводиться звичайний String у Java під час частих змін.

2. StringBuilder: швидкий «будівничий» рядків

Клас StringBuilder (пакет java.lang — імпортувати не потрібно) — це спеціальний інструмент для ефективного збирання та зміни рядків. Він змінюваний (mutable): можна додавати, видаляти, вставляти символи та підрядки без створення нового обʼєкта на кожну операцію.

Аналогія:
Якщо String — це бетонна плита, то StringBuilder — конструктор LEGO: додаєте й прибираєте деталі скільки завгодно, не розбираючи все заново.

Як створити StringBuilder

StringBuilder sb = new StringBuilder(); // порожній
StringBuilder sb2 = new StringBuilder("Початкове значення");

Основні методи

Метод Опис Приклад використання
append(...)
Додати у кінець рядок, число, символ тощо.
sb.append("Java");
insert(index, ...)
Вставити значення у зазначену позицію.
sb.insert(0, "Hello ");
delete(start, end)
Видалити символи з позиції start (включно) до end (невключно).
sb.delete(0, 5);
replace(start, end, str)
Замінити частину рядка іншим вмістом.
sb.replace(0, 4, "Hi");
reverse()
Розвернути рядок задом наперед.
sb.reverse();
toString()
Перетворити на звичайний рядок.
String s = sb.toString();
setLength(newLen)
Обрізати або доповнити рядок до заданої довжини.
sb.setLength(3);

Приклад використання

StringBuilder sb = new StringBuilder();
sb.append("Привіт, ");
sb.append("світ!");
System.out.println(sb); // Привіт, світ!

sb.insert(7, "Java "); // вставимо "Java " після "Привіт, "
System.out.println(sb); // Привіт, Java світ!

sb.replace(8, 12, "інший"); // замінимо "Java" на "інший"
System.out.println(sb); // Привіт, інший світ!

sb.reverse();
System.out.println(sb); // !тівс йишні ,тівирП

3. StringBuffer: старший брат із потокобезпекою

У чому різниця між StringBuilder і StringBuffer?

  • StringBuilder — швидший, але непотокобезпечний (несинхронізований).
  • StringBuffer — повільніший, але потокобезпечний (синхронізований).

Якщо ваш застосунок працює в одному потоці — використовуйте StringBuilder (швидше). Якщо кілька потоків можуть змінювати один і той самий рядок — використовуйте StringBuffer.

4. Коли використовувати StringBuilder замість String?

Сценарії

  • Часті зміни рядка (додавання, видалення, вставка) у циклі або під час збирання великих текстів.
  • Збирання рядка з масиву або списку (CSV, HTML, звіти тощо).
  • Розбір і обробка тексту з великою кількістю операцій над рядком.

Приклад: збирання рядка з масиву

Поганий спосіб (через String і +):

String[] names = {"Іван", "Петро", "Марія"};
String result = "";

for (int i = 0; i < names.length; i++) 
{
    result += names[i];
    if (i < names.length - 1) 
    {
        result += ", ";
    }
}
System.out.println(result);

Хороший спосіб (через StringBuilder):

String[] names = {"Іван", "Петро", "Марія"};
StringBuilder sb = new StringBuilder();

for (int i = 0; i < names.length; i++) 
{
    sb.append(names[i]);
    if (i < names.length - 1) 
    {
        sb.append(", ");
    }
}
System.out.println(sb.toString());

Різниця: у першому випадку на кожному кроці створюється новий рядок, у другому — ви нарощуєте один обʼєкт StringBuilder.

5. Порівняння продуктивності: String vs StringBuilder


// Через String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
    s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " мс");

// Через StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
    sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " мс");

Підсумок: у більшості випадків StringBuilder працює значно швидше під час множинних конкатенацій.

6. Корисні нюанси

Чи можна використовувати методи String?
StringBuilder має власні методи. Щоб отримати рядок, викликайте toString().

StringBuilder sb = new StringBuilder("Привіт");
String s = sb.toString(); // тепер s — звичайний рядок

Чи можна порівнювати StringBuilder через equals?
Увага: sb1.equals(sb2) порівнює посилання, а не вміст. Порівнюйте так:

if (sb1.toString().equals(sb2.toString())) 
{
    // вміст збігається
}

Чи можна передати StringBuilder у System.out.println?
Так. System.out.println автоматично викличе toString().

Чи можна читати символи за індексом?
Так, використовуйте charAt(int index), як у звичайного рядка.

7. Типові помилки під час роботи з StringBuilder і StringBuffer

Помилка № 1: порівнювати два StringBuilder через equals або оператор ==. Ці перевірки порівнюють посилання, а не вміст. Використовуйте toString() і порівняння рядків.

Помилка № 2: забувати викликати toString() там, де очікується String (повернення з методу, логування, передавання в API).

Помилка № 3: застосовувати StringBuilder для кількох простих конкатенацій. Запис виду "Hello, " + name нормально читається й достатньо ефективний.

Помилка № 4: конкатенувати String у циклі через +. Це неефективно за часом і памʼяттю — використовуйте StringBuilder.

Помилка № 5: плутати StringBuffer і StringBuilder без потреби. Якщо немає спільної модифікації з кількох потоків — обирайте StringBuilder.

Помилка № 6: бездумно обрізати вміст StringBuilder методом setLength(). Перевіряйте коректність нової довжини — дані після неї будуть втрачені.

1
Опитування
Робота з рядками, рівень 9, лекція 5
Недоступний
Робота з рядками
Робота з рядками
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ