Найкращі практики / продуктивність: змішування 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

Відповіді:


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, яка є пулом рядків. Використання конструктора рядків зберігає все як символ [] і не створює проміжний рядок, як це робив оператор + до оптимізації компілятора (використовується просто для створення конката). Використання concat створює проміжний об’єкт String, який кешований, але не використовується.
LINEMAN78,

Отже, якщо я роблю одноразовий оператор (а не кілька операторів по методу), об’єднання в кілька різних рядків. Було б добре використовувати +об’єкти String замість того, щоб створювати StringBuilderдля цього одноразового об’єднання, оскільки це в основному буде робити те саме?
Нік Роландо,

1
І якщо я хочу зв’язати лише символ, чи краще використовувати .append ('\ n') замість .append ("\ n")? Як символ - примітивний тип, а рядок - це об’єкт?
vrwim

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();

Взято безпосередньо з веб-сайту Best Practices on Oracles.


2

Ви завжди повинні використовувати append.

concatстворити новий рядок, щоб це було так, як +я думаю.

Якщо ви concatвикористовуєте або використовуєте +2 final String, JVM може зробити оптимізацію, тож це те саме, що зробити додавання в цьому випадку.


1

Якщо ви поєднуєте рівно два рядки, використовуйте String.concat (створює новий рядок, створюючи новий char-масив, який підходить як для Strings, так і копіює в нього обидва char-масиви).

Якщо ви поєднуєте кілька (більше двох) рядків в одному рядку, використовуйте + або StringBuilder.append, це не має значення, оскільки компілятор перетворює + у StringBuilder.append. Це добре для декількох рядків, оскільки він підтримує один масив символів, який зростає за потреби.

Якщо ви поєднуєте кілька рядків у декількох рядках, створіть один StringBuilder і використовуйте метод append. Врешті-решт, коли ви закінчите додавати рядки до StringBuilder, використовуйте метод .toString () - для створення з нього рядка. Для конкатату в декількох рядках це швидше, ніж другий метод, оскільки другий метод створить новий StringBuilder у кожному рядку, додасть рядки, а потім поверне до String, тоді як третій метод використовує лише один StringBuilder для всього.


0

+Оператор використання - найкраща практика, він також простий і читабельний.

Мова Java забезпечує спеціальну підтримку оператора конкатенації рядків (+) та перетворення інших об'єктів у рядки. Конкатенація рядків реалізується за допомогою класу StringBuilder (або StringBuffer) та методу його додавання.

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


0

на рівні байтового коду не відрізняється, і ми там не порушуємо ефективність. У випадку виконання рівня байтового коду, він повинен пройти через невбудований метод перевантаження оператора для + за допомогою виклику append. потім на рівні мови асемблера (Java пишеться на C, а C створює збірки, схожі на збірку, буде додатковий виклик регістру для збереження + виклик методу в стеку та додатковий натиск. (насправді крос-компілятор може оптимізувати + оператор дзвінок, у цьому випадку це не впливає на ефективність.)

Це хороша практика - мати один із способів підвищити читабельність. :)


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

0

Усі відповіді досить добрі та пояснювальні. Але я відчував, що дослідження інших методів конкатенації рядків також можуть допомогти - Guava Joiner, Streams, String.format тощо.

Повні подробиці щодо продуктивності кожного методу конкатенації java-string-concatenation-which-way-is-best .

Коротше кажучи, ефективність об'єднання варіюється в залежності від значення. рядків для об'єднання. Наприклад - для об’єднання 1-10 рядків ці методи найкраще працюють - StringBuilder, StringBuffer та Plus Operator. А для об’єднання 100-х рядків - Guava Joiner, бібліотека stringsUtils apache також чудово працює.

Будь ласка, перейдіть до вищенаведеного блогу Це дійсно дуже добре пояснює ефективність роботи.

Дякую.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.