← Назад к вопросам

В чем разница между конкатенацией и методом append в StringBuilder?

1.0 Junior🔥 121 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между конкатенацией и StringBuilder.append()

Конкатенация со строками через +

Когда вы используете оператор +, Java компилирует это в вызовы StringBuilder под капотом, но неэффективно в циклах:

// Конкатенация
String str = "";
for (int i = 0; i < 1000; i++) {
    str = str + "hello";  // создаёт НОВЫЙ объект на каждой итерации!
}

Это эквивалентно:

String str = "";
for (int i = 0; i < 1000; i++) {
    str = new StringBuilder(str)
        .append("hello")
        .toString();  // преобразование в String
}

Каждая итерация создаёт новый StringBuilder, добавляет текст и преобразует обратно в String. Это очень неэффективно!

StringBuilder.append()

StringBuilder - это мутируемый класс, который растёт по мере необходимости:

// StringBuilder - правильный подход
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("hello");  // добавляет в существующий объект
}
String result = sb.toString();  // преобразование один раз в конце

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

Производительность

Разница в производительности огромна:

public class StringPerformanceTest {
    public static void main(String[] args) {
        // Конкатенация - медленно
        long start = System.currentTimeMillis();
        String result1 = "";
        for (int i = 0; i < 10000; i++) {
            result1 = result1 + "text";  // O(n²) временная сложность
        }
        long concatTime = System.currentTimeMillis() - start;
        System.out.println("Конкатенация: " + concatTime + "ms");  // ~1000ms+
        
        // StringBuilder - быстро
        start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append("text");  // O(n) временная сложность
        }
        String result2 = sb.toString();
        long sbTime = System.currentTimeMillis() - start;
        System.out.println("StringBuilder: " + sbTime + "ms");  // ~1ms
        
        // Результат: конкатенация медленнее в 1000+ раз!
    }
}

Внутренняя реализация StringBuilder

StringBuilder содержит массив символов и индекс текущей позиции:

public class StringBuilder extends AbstractStringBuilder {
    char[] value;      // внутренний массив
    int count;         // текущая длина
    
    public StringBuilder append(String str) {
        if (str == null) {
            return appendNull();
        }
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);  // копирует в массив
        count += len;
        return this;
    }
    
    private void ensureCapacityInternal(int minimumCapacity) {
        if (minimumCapacity - value.length > 0) {
            // расширяем массив
            char[] newValue = new char[newCapacity];
            System.arraycopy(value, 0, newValue, 0, count);
            value = newValue;
        }
    }
}

Массив растёт по мере необходимости, обычно в 2 раза, что амортизирует стоимость копирования.

Одиночная конкатенация

Для одиночной конкатенации разницы практически нет:

// Так OK - компилятор оптимизирует
String greeting = "Hello " + "World";  // компилируется в "Hello World"

// Так тоже OK для отдельных операций
String full = firstName + " " + lastName;  // приемлемо

// Но в цикле - ПЛОХО
for (String s : collection) {
    result = result + s;  // никогда так не делай!
}

StringBuffer vs StringBuilder

StringBuffer - это синхронизированная версия StringBuilder:

// StringBuffer - потокобезопасен (синхронизирован)
public synchronized StringBuffer append(String str) {
    // ...
}

// StringBuilder - НЕ потокобезопасен (быстрее)
public StringBuilder append(String str) {
    // ...
}

Используй StringBuilder если не требуется многопоточность (обычно это так).

Лучшие практики

// ❌ ПЛОХО - конкатенация в цикле
String result = "";
for (User user : users) {
    result = result + user.getName() + ",";
}

// ✅ ХОРОШО - StringBuilder
StringBuilder sb = new StringBuilder();
for (User user : users) {
    sb.append(user.getName()).append(",");
}
String result = sb.toString();

// ✅ ХОРОШО - методы join() при наличии
String result = String.join(",", 
    users.stream().map(User::getName).collect(Collectors.toList()));

// ✅ ХОРОШО - Streams
String result = users.stream()
    .map(User::getName)
    .collect(Collectors.joining(","));

Вывод

Конкатенация через + создаёт новый StringBuilder на каждой итерации, что приводит к O(n²) временной сложности. StringBuilder.append() создаёт один объект с растущим массивом, что даёт O(n) сложность. Всегда используй StringBuilder для построения строк в циклах и при множественных операциях.

В чем разница между конкатенацией и методом append в StringBuilder? | PrepBro