Строки являются неизменяемыми - это означает, что я никогда не должен использовать + = и только StringBuffer? - PullRequest
11 голосов
/ 28 октября 2009

Строки являются неизменяемыми, то есть после создания они не могут быть изменены.

Итак, означает ли это, что если вы добавите вещи с помощью + =, потребуется больше памяти, чем если бы вы создали StringBuffer и добавили к нему текст?

Если вы используете + =, вы бы каждый раз создавали новый «объект», который нужно сохранить в памяти, не так ли?

Ответы [ 11 ]

25 голосов
/ 28 октября 2009

Да, вы будете создавать новый объект каждый раз с + =. Это не значит, что это всегда неправильно. Это зависит от того, хотите ли вы это значение в виде строки или просто собираетесь использовать его для дальнейшего построения строки.

Если вы на самом деле хотите результат x + y в виде строки, то вы также можете просто использовать конкатенацию строк. Однако, если вы действительно собираетесь (скажем) зацикливаться и добавлять еще одну строку, другую и т. Д., Для которых нужен только результат в виде строки в самом конце, тогда StringBuffer / StringBuilder - это то, что вам нужно. Действительно, в цикле StringBuilder окупается за конкатенацию строк - разница в производительности для 5 или даже 10 прямых конкатенаций будет довольно небольшой, но для тысяч она станет намного хуже - в основном потому, что вы получаете O (N 2) ) сложность с конкатенацией и сложностью O (N) с StringBuilder.

В Java 5 и выше вы должны в основном использовать StringBuilder - он не синхронизирован, но это почти всегда нормально; очень редко хочется поделиться одним потоком.

У меня есть статья обо всем этом , которая может оказаться вам полезной.

7 голосов
/ 28 октября 2009

Простое правило:

Если вы запускаете конкатенации в цикле, не используйте +=

Если вы не выполняете конкатенации в цикле, использование += просто не имеет значения. (Если только приложение не критично к производительности

5 голосов
/ 28 октября 2009

Я согласен со всеми ответами, опубликованными выше, но это поможет вам немного лучше понять, как реализована Java. JVM использует StringBuffers для компиляции оператора String + (из StringBuffer Javadoc ):

Строковые буферы используются компилятор для реализации бинарного оператор конкатенации строк +. За Например, код:

     x = "a" + 4 + "c"

компилируется в эквивалент:

     x = new StringBuffer().append("a").append(4).append("c")
                           .toString()

Аналогично, x += "some new string" эквивалентно x = x + "some new string". Вы видите, куда я иду с этим?

Если вы делаете много конкатенаций String, использование StringBuffer повысит вашу производительность, но если вы делаете только пару простых конкатенаций String, компилятор Java, вероятно, оптимизирует его для вас, и вы не заметите разница в производительности

5 голосов
/ 28 октября 2009

В Java 5 или более поздней версии StringBuffer является потокобезопасным, и поэтому имеет некоторые накладные расходы, за которые вы не должны платить, если вам это не нужно. StringBuilder имеет тот же API, но не является поточно-ориентированным (т.е. вы должны использовать его только внутри одного потока).

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

3 голосов
/ 28 октября 2009

Да. Строка неизменна. + Для случайного использования + = в порядке. Если операция + = интенсивная, вам следует обратиться к StringBuilder.

1 голос
/ 28 октября 2009

Но сборщик мусора в итоге освободит старые строки, если на них нет ссылок

1 голос
/ 28 октября 2009

Точно. Вы должны использовать StringBuilder, хотя, если безопасность потока не является проблемой.

В качестве примечания: может быть несколько объектов String, использующих один и тот же задний символ [] - например, всякий раз, когда вы используете substring (), новый символ [] не создается, что делает его весьма эффективным.

Кроме того, компиляторы могут выполнить некоторую оптимизацию для вас. Например, если вы делаете

static final String FOO = "foo";
static final String BAR = "bar"; 

String getFoobar() {
  return FOO + BAR; // no string concatenation at runtime
}

Я не удивлюсь, если компилятор будет использовать StringBuilder для оптимизации строковой конкатенации, где это возможно, если не в будущем.

0 голосов
/ 28 октября 2009
нет

Нет

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

0 голосов
/ 28 октября 2009

Вы правы, что строки являются неизменяемыми, поэтому, если вы пытаетесь сохранить память при выполнении большого количества конкатенации строк, вам следует использовать StringBuilder вместо + =.

Однако вы можете не возражать. Программы написаны для их читателей-людей, поэтому вы можете идти с ясностью. Если вам важно оптимизировать, вы должны сначала профиль. Если ваша программа не сильно увлечена строковой активностью, вероятно, будут другие узкие места.

0 голосов
/ 28 октября 2009

Да, так и есть, и именно поэтому вы должны использовать StringBuffer для объединения большого количества строк.

Также обратите внимание, что начиная с Java 5, вы также должны предпочитать StringBuilder большую часть времени. Это просто какой-то несинхронизированный StringBuffer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...