StringBuilder / StringBuffer против оператора "+" - PullRequest
35 голосов
/ 10 января 2011

Я читаю " Лучше, Быстрее, Легче Java " (Брюс Тейт и Джастин Гетланд) и знаком с требованиями читабельности в командах гибкого типа, такими как то, что Роберт Мартин обсуждает в своем чистом кодирование книг. В команде, в которой я сейчас работаю, мне прямо сказали не использовать оператор +, потому что он создает дополнительные (и ненужные) строковые объекты во время выполнения.

Но эта статья , написанная еще в '04, рассказывает о том, как распределение объектов составляет около 10 машинных инструкций. (в основном бесплатно)

В нем также говорится о том, как GC также помогает снизить затраты в этой среде.

Каков фактический компромисс производительности между использованием +, StringBuilder или StringBuffer? (В моем случае это StringBuffer только потому, что мы ограничены Java 1.4.2.)

StringBuffer для меня приводит к уродливому, менее читабельному коду, как показывает пара примеров в книге Тейта. И StringBuffer является синхронизированным потоком, который, кажется, имеет свои собственные затраты, которые перевешивают «опасность» при использовании оператора +.

Мысли / мнения

Ответы [ 3 ]

48 голосов
/ 10 января 2011

Использование String конкатенации преобразуется компилятором в StringBuilder операции.

Чтобы посмотреть, как работает компилятор, я возьму пример класса, скомпилирую его и декомпилирую с помощью jad, чтобы увидеть, что генерирует байт-код.

Оригинальный класс:

public void method1() {
    System.out.println("The answer is: " + 42);
}

public void method2(int value) {
    System.out.println("The answer is: " + value);
}

public void method3(int value) {
    String a = "The answer is: " + value;
    System.out.println(a + " what is the question ?");
}

Декомпилированный класс:

public void method1()
{
    System.out.println("The answer is: 42");
}

public void method2(int value)
{
    System.out.println((new StringBuilder("The answer is: ")).append(value).toString());
}

public void method3(int value)
{
    String a = (new StringBuilder("The answer is: ")).append(value).toString();
    System.out.println((new StringBuilder(String.valueOf(a))).append(" what is the question ?").toString());
}
  • На method1 компилятор выполнил операцию во время компиляции.
  • При method2 конкатенация String эквивалентна использованию вручную StringBuilder.
  • При method3 конкатенация String определенно плоха, так как компилятор создает второй StringBuilder вместо повторного использования предыдущего.

Таким образом, мое простое правило состоит в том, что конкатенации хороши, если только вам не нужно конкатенировать результат снова: например, в циклах или когда вам нужно сохранить промежуточный результат.

22 голосов
/ 10 января 2011

Ваша команда должна узнать о причинах, препятствующих повторному объединению строк .

Конечно, бывают случаи, когда имеет смысл использовать StringBuffer -особенно когда вы создаете строку в цикле, особенно если вы не уверены , что в цикле будет мало итераций.Обратите внимание, что дело не только в создании новых объектов - это в копирование всех текстовых данных, которые вы уже добавили.Также имейте в виду, что распределение объектов является «по существу свободным», если вы не учитываете сборку мусора.Да, если в текущем поколении достаточно места, это в основном вопрос увеличения указателя ... но:

  • Эта память должна быть очищена в какой-то момент.Это не бесплатно.
  • Вы сокращаете время до следующего GC.GC не является бесплатным.
  • Если ваш объект живет в следующем поколении, очистка может занять больше времени - опять же, не бесплатно.

Все эти вещи достаточно дешево в том смысле, что "обычно" не стоит отгибать дизайн от элегантности, чтобы избежать создания объектов ... но вы не должны рассматривать их как free .

С другой стороны, нет смысла использовать StringBuffer в тех случаях, когда вам не нужны промежуточные строки.Например:

String x = a + b + c + d;

эффективен как минимум:

StringBuffer buffer = new StringBuffer();
buffer.append(a);
buffer.append(b);
buffer.append(c);
buffer.append(d);
String x = buffer.toString();
5 голосов
/ 10 января 2011

Для небольших объединений вы можете просто использовать String и + для удобства чтения. Производительность не пострадает. Но если вы выполняете много операций конкатенации, используйте StringBuffer.

...