Лучшие практики / производительность: смешивание StringBuilder.append с String.concat

86

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

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

Это способ сделать это? Из этого поста я заметил, что +оператор в Strings создает новый экземпляр StringBuilder, объединяет операнды и возвращает преобразование String, что, похоже, требует гораздо больше работы, чем просто вызов .append(); так что если это правда, то об этом не может быть и речи. А что насчет String.concat()? Правильно ли использовать .append()для каждой конкатенации? Или только для переменных и литералов можно добавлять .concat()?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

Каковы общие правила передового опыта и производительности в подобных ситуациях? Верно ли мое предположение, +и его действительно не следует использовать?

Ник Роландо
источник
Я думаю, что в основном это у вас есть. Мнения расходятся относительно того, действительно ли String + «не следует использовать». Дело в том, что вы понимаете последствия
ControlAltDel 09

Ответы:

184

+ оператор

String s = s1 + s2

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

String s = new StringBuilder(s1).append(s2).toString();

Представьте, сколько дополнительной работы он добавляет, если у вас есть s1 + s2здесь:

stringBuilder.append(s1 + s2)

вместо того:

stringBuilder.append(s1).append(s2)

Несколько строк с +

Стоит отметить, что:

String s = s1 + s2 + s3 + ... +sN

переводится на:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

Stringсоздает char[]массив, который может вместить как s1и s2. Копии s1и s2содержимое этого нового массива. На самом деле требует меньше работы, чем +оператор.

StringBuilder.append()

Поддерживает внутренний char[]массив, который увеличивается при необходимости. Никакого лишнего char[]не создается, если внутренний достаточно большой.

stringBuilder.append(s1.concat(s2))

также работает плохо , потому что s1.concat(s2)создает дополнительный char[]массив и копирует s1и s2к нему просто скопировать , что новое содержимое массива к внутреннему StringBuilder char[].

При этом вы должны использовать append()все время и добавлять необработанные строки (ваш первый фрагмент кода правильный).

Томаш Нуркевич
источник
Спасибо за вашу помощь и подробное объяснение; вот что мне действительно нужно.
Ник Роландо,
12
Хотя более новые версии компилятора автоматически оптимизируют оператор + для построителя строк, не обязательно предполагать, что это будет так, как в старых версиях. Во всем этом обсуждении игнорируется очень важная тема, которая на самом деле является одной из основных целей StringBuilder, который является пулом строк. Использование построителя строк сохраняет все как char [] и не создает промежуточную строку, как это делал оператор + перед оптимизацией компилятора (использовался только для выполнения concat). Использование concat создает промежуточный объект String, который кэшируется, но не используется.
LINEMAN78
Итак, если я выполняю одноразовый оператор (а не несколько операторов в методе), объединение нескольких разных строк. Было бы нормально использовать +объекты String вместо создания StringBuilderодноразовой конкатенации, поскольку она в основном будет делать то же самое?
Ник Роландо,
1
И если я хочу объединить только символ, что лучше использовать .append ('\ n') вместо .append ("\ n")? Поскольку символ - это примитивный тип, а String - это объект?
vrwim 07
3
Эффективное 2-е издание Java : многократное использование оператора конкатенации строк для конкатенации n строк требует времени, квадратичного по n. Так все еще актуально?
gkiko
16

Компилятор оптимизирует конкатенацию +.

Так

int a = 1;
String s = "Hello " + a;

превращается в

new StringBuilder().append("Hello ").append(1).toString();

Там отличная тема здесь объяснить , почему вы должны использовать оператор +.

Энди Тернер
источник
3
Компилятор фактически оптимизирует это, String s = "Hello World";поскольку вы используете литералы.
ColinD
@ColinD: +1. Только что изменил свой фрагмент.
3

Оптимизация выполняется компилятором автоматически.

Компилятор Java2 автоматически преобразует следующее:

String s = s1 + s2; 

к

String s = (new StringBuffer()).append(s1).append(s2).toString();

Взято прямо с веб-сайта Java Best Practices on Oracles.

Жирный, как любовь
источник
2

Вы всегда должны использовать append.

concatсоздать новую строку так, как +я думаю.

Если вы concatили используете +с 2 final String, JVM может выполнить оптимизацию, так что это то же самое, что и добавление в этом случае.

alain.janinm
источник
1

Если вы объединяете ровно две строки, используйте String.concat (создает новую строку, создавая новый массив символов, который соответствует обеим строкам, и копирует в него массивы символов обеих строк).

Если вы объединяете несколько (более двух) строк в одну строку, используйте + или StringBuilder.append, это не имеет значения, поскольку компилятор преобразует + в StringBuilder.append. Это хорошо для нескольких строк, поскольку поддерживает один массив символов, который увеличивается по мере необходимости.

Если вы объединяете несколько строк в несколько строк, создайте один StringBuilder и используйте метод append. В конце, когда вы закончите добавление Strings в StringBuilder, используйте его .toString () - метод, чтобы создать из него String. Для объединения в несколько строк это быстрее, чем второй метод, поскольку второй метод будет создавать новый StringBuilder в каждой строке, добавлять строки и затем возвращать их к String, тогда как третий метод использует только один StringBuilder для всего этого.

Даккарон
источник
0

+Лучше всего использовать оператор использования , он также прост и удобочитаем.

В языке Java предусмотрена специальная поддержка оператора конкатенации строк (+) и преобразования других объектов в строки. Конкатенация строк реализуется с помощью класса StringBuilder (или StringBuffer) и его метода добавления.

Официальный документ: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

До Нху Ви
источник
0

на уровне байт-кода нет различий, и мы не ставим под угрозу эффективность. В случае выполнения уровня байтового кода он должен пройти через метод перегрузки не встроенного оператора для +, вызвав append. затем на уровне языка ассемблера (Java написана на C, а C создает сборки, аналогичные сборке, будет дополнительный вызов регистра для вызова метода store + в стеке, и будет дополнительный push. (на самом деле кросс-компилятор может оптимизировать оператор + звоните, в этом случае не имеет значения для эффективности.)

Хорошая практика - иметь один способ повысить удобочитаемость. :)

Шевон Сильва
источник
0

Лично я предпочитаю Strings.format()простой и удобный для чтения однострочный форматтер строк .

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F
T04435
источник
0

Все ответы довольно хороши и понятны. Но я чувствовал, что изучение других методов конкатенации строк также может помочь, например, Guava Joiner, Streams, String.format и т. Д.

Для получения полной информации о производительности каждого метода конкатенации java-string-concatenation-which-way-is-best .

Вкратце, производительность конкатенации зависит от номера. строк для объединения. Например, для объединения 1-10 строк лучше всего подходят эти методы - StringBuilder, StringBuffer и Plus Operator. А для объединения сотен строк - Guava Joiner, библиотека apache stringsUtils также отлично работает.

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

Спасибо.

coderAJ
источник