Строки неизменяемы - это означает, что мне никогда не следует использовать +=, а только StringBuffer?

StackOverflow https://stackoverflow.com/questions/1635659

Вопрос

Строки неизменяемы, то есть после создания их нельзя изменить.

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

  

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

     x = "a" + 4 + "c"
     

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

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

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

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

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

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

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

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

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

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

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

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

Я думаю, что GC собирает память с оставленной строкой. Таким образом, выполнение + = со строителем строк будет определенно быстрее, если у вас есть много операций по обработке строк. Но это не должно быть проблемой для большинства случаев.

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

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

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

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

Нет

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top