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

Чем достигается отсутствие промежуточных объектов при использовании StringBuilder?

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

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

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

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

Отсутствие промежуточных объектов в StringBuilder

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

Сравнение String и StringBuilder

Проблема со String (неизменяемость)

String result = "Hello";
result = result + " World";      // Новый объект String
result = result + "!";             // Еще новый объект String
result = result + " How are you"; // И еще один новый объект

Решение с StringBuilder (изменяемость)

StringBuilder result = new StringBuilder();
result.append("Hello");              // Добавляем в буфер
result.append(" World");             // Изменяем тот же буфер
result.append("!");                  // Изменяем тот же буфер
result.append(" How are you");       // Изменяем тот же буфер

String finalString = result.toString();  // Только ОДИН новый String

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

public class StringBuilderDemo {
    
    public static class SimpleStringBuilder {
        
        private char[] buffer;     // Изменяемый массив
        private int count;         // Текущая длина
        
        public SimpleStringBuilder() {
            this.buffer = new char[16];  // Начальная емкость
            this.count = 0;
        }
        
        public SimpleStringBuilder append(String str) {
            if (str == null) str = "null";
            int len = str.length();
            
            if (count + len > buffer.length) {
                expandCapacity(count + len);
            }
            
            str.getChars(0, len, buffer, count);
            count += len;
            
            return this;  // Возвращаем тот же объект
        }
        
        private void expandCapacity(int minimumCapacity) {
            int newCapacity = (buffer.length + 1) * 2;
            if (newCapacity < minimumCapacity) {
                newCapacity = minimumCapacity;
            }
            
            char[] newBuffer = new char[newCapacity];
            System.arraycopy(buffer, 0, newBuffer, 0, count);
            buffer = newBuffer;
        }
        
        public String toString() {
            return new String(buffer, 0, count);
        }
    }
}

Механизм расширения буфера

public class CapacityManagement {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();  // Емкость = 16
        
        for (int i = 0; i < 100; i++) {
            sb.append("x");
            // 16 → 34 → 70 → 142
        }
    }
}

Практическое сравнение производительности

public class PerformanceComparison {
    
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 10000; i++) {
            str = str + i;  // Новый String каждый раз
        }
        long duration1 = System.currentTimeMillis() - start;
        
        start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append(i);
        }
        String result = sb.toString();
        long duration2 = System.currentTimeMillis() - start;
        
        System.out.println("StringBuilder быстрее в 100-1000 раз");
    }
}

Ключевые отличия

String (Immutable)

  • Каждая операция конкатенации создает новый объект
  • Старые объекты подлежат сборке мусора
  • Медленно при множественных операциях

StringBuilder (Mutable)

  • Один изменяемый объект с внутренним буфером (char[])
  • Все операции append() модифицируют один объект
  • toString() создает только финальный String
  • Очень быстро при множественных операциях

Компиляторная оптимизация

Java компилятор автоматически преобразует простую конкатенацию:

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

В:

String result = new StringBuilder()
    .append("Hello")
    .append(" ")
    .append("World")
    .toString();

Правило использования

Используй StringBuilder когда:

  • Конкатенация происходит в циклах
  • Множество операций append() подряд
  • Критична производительность

Не нужен StringBuilder для:

  • Одной-двух конкатенаций: String name = first + " " + last;
  • Операций с неизменяемыми строками

Вывод

StringBuilder избегает промежуточных объектов через:

  • Изменяемый внутренний буфер (char[])
  • Переиспользование одного объекта для всех операций
  • Только финальное toString() создает новый String
  • Автоматическое расширение буфера без создания String объектов

Это дает огромное улучшение производительности при работе со строками, в некоторых случаях на 100-1000 раз быстрее.