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

Из-за чего в куче не создается лишних строк при использовании StringBuilder

1.8 Middle🔥 131 комментариев
#Основы Java

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

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

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

Из-за чего в куче не создается лишних строк при использовании StringBuilder

Это ключевая деталь, которая показывает понимание внутреннего устройства Java и управления памятью. Давайте разберёмся, почему StringBuilder не создаёт промежуточные String объекты.

Проблема с обычным конкатенированием

Сначала посмотрим на проблему:

String result = "Hello" + " " + "World" + " " + "Java";

Кажется просто, но на самом деле создаётся много промежуточных объектов:

  1. "Hello" — 1 объект
  2. "Hello " — 2-й объект (новый)
  3. "Hello World" — 3-й объект (новый)
  4. "Hello World " — 4-й объект (новый)
  5. "Hello World Java" — 5-й объект (финальный)

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

Как работает StringBuilder

StringBuilder использует принципиально другой подход:

StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
sb.append(" ");
sb.append("Java");
String result = sb.toString();  // Только здесь создаётся один String

Внутреннее устройство StringBuilder

StringBuilder основана на массиве символов (char[]):

public class StringBuilder {
    private char[] value;  // Внутренний буфер
    private int count;     // Текущий размер
    
    // append просто добавляет в массив
    public StringBuilder append(String str) {
        if (str == null) {
            appendNull();
            return this;
        }
        int len = str.length();
        ensureCapacityInternal(count + len);  // Расширить если нужно
        str.getChars(0, len, value, count);   // Скопировать в буфер
        count += len;
        return this;
    }
    
    // toString создаёт единственный String
    public String toString() {
        return new String(value, 0, count);
    }
}

Почему нет лишних объектов?

  1. Нет промежуточных String объектов: На протяжении всех append() операций мы работаем только с внутренним массивом char[]

  2. String создаётся только один раз: Только при вызове toString() создаётся финальный String объект

  3. Эффективный буфер: Если буфер маленький, он автоматически расширяется (обычно удваивается)

private void ensureCapacityInternal(int minimumCapacity) {
    if (minimumCapacity - value.length > 0) {
        expandCapacity(minimumCapacity);
    }
}

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);
}

Сравнение памяти

С обычным конкатенированием:

Время: O(n²) — каждое добавление копирует всю строку
Память: O(n²) — создаётся O(n) промежуточных объектов

С StringBuilder:

Время: O(n) — амортизированная сложность
Память: O(n) — создаётся 1 финальный объект + расходы на буфер

Пример из реального проекта

// Плохо: создаст 1000+ объектов
String result = "";
for (int i = 0; i < 1000; i++) {
    result += "Item" + i + ", ";  // Каждая итерация — новый String
}

// Хорошо: создаст 1 объект
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("Item").append(i).append(", ");
}
String result = sb.toString();

StringBuffer vs StringBuilder

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

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

Из-за чего в куче не создается лишних строк при использовании StringBuilder | PrepBro