2013-02-18 2 views
40

В статье this answer говорится (подразумевает), что конкатенация строк в любом случае оптимизирована для операций StringBuilder, поэтому, когда я пишу свой код, есть ли какие-либо причины для написания кода StringBuilder в источнике? Обратите внимание, что мой вариант использования отличается от вопроса OP, поскольку я конкатенирую/добавляю сотни тысяч строк.Java: String concat vs StringBuilder - оптимизирован, поэтому что мне делать?

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

+1

Вот хороший анализ: http://www.javacodegeeks.com/2013/03/java-stringbuilder-myth-debunked.html – marcolopes

ответ

105

Я думаю, что использование StringBuilder против + действительно зависит от контекста, вы используете его.

В целом с использованием JDK 1.6 и выше компилятор автоматически соединит строки вместе, используя StringBuilder.

String one = "abc"; 
String two = "xyz"; 
String three = one + two; 

будет скомпилирован String three как:

String three = new StringBuilder().append(one).append(two).toString(); 

Это весьма полезно и экономит некоторое время работы. Однако этот процесс не всегда оптимален. Возьмем, к примеру:

String out = ""; 
for(int i = 0; i < 10000 ; i++) { 
    out = out + i; 
} 
return out; 

Если компилировать байткод, а затем декомпилировать байт-код генерируется мы получаем что-то вроде:

String out = ""; 
for(int i = 0; i < 10000; i++) { 
    out = new StringBuilder().append(out).append(i).toString(); 
} 
return out; 

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

StringBuilder out = new StringBuilder(); 
for(int i = 0 ; i < 10000; i++) { 
    out.append(i); 
} 
return out.toString(); 

Теперь это более оптимальным, чем компилятор сгенерированный код, так что, безусловно, нужно писать код, используя классы StringBuilder/StringBuffer в тех случаях, когда требуется эффективный код. Текущие компиляторы не очень эффективны при конкатенации строк в цикле, однако это может измениться в будущем.

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

Примечание. Я скомпилировал код с использованием JDK 1.6 и декомпилировал код с помощью программы javap, которая выплевывает байт-код. Его довольно легко интерпретировать и часто полезно использовать при попытке оптимизировать код. Компилятор меняет ваш код за кулисами, поэтому всегда интересно посмотреть, что он делает!

+3

Является ли ваш декомпилированный код (во втором для цикла) результатом фактической декомпиляции, или это ваша догадка? Если вы отлаживаете цикл for/while с конкатенацией строк «+» в нем, вы обнаружите, что объект StringBuilder не воссоздается в каждом цикле, но на самом деле тот же самый используется повторно. В противном случае, если вы подставляете более тяжелый объект (т. Е. StringBuilder для String), какую оптимизацию вы действительно получаете? –

+2

Я хотел бы узнать ответ на вопрос @SpencerKormos. Создает ли компилятор новый 'StringBuilder' для каждой итерации цикла? Почему это было бы оптимально? – ryvantage

+0

Перечитывая ответ и ссылку в вопросе OP, точка, которую делал Том, заключалась в том, что если операция concat происходит в цикле, тогда компилятор не будет оптимизировать общий блок кода (который будет включать в себя петля). В этом случае вы должны объявить свой цикл StringBuilder * before * for и использовать append() внутри цикла, что сделает операцию concat наиболее эффективной (т. Е. Последний блок кода от Tom). Надеюсь, что это имеет смысл, и спасибо, что вернули мне это! –

0

Возможно, я неправильно понял ваш вопрос, но StringBuilder быстрее при добавлении строк. Итак, да, если вы добавляете «сотни тысяч строк», вам определенно следует использовать StringBuilder (или StringBuffer, если вы используете многопоточное приложение).

(Более тщательный ответ в комментариях)

+1

По-видимому, современные/зрелые компиляторы Java достаточно умны, чтобы преобразовывать операции конкатенации в операции добавления строк в StringBuilder, так какой смысл использовать StringBuilder в коде, когда он менее читабельный, и когда String concats преобразуются в операции StringBuilder? – Soyuz

+2

О, теперь я вижу твою точку, приятель. Да, вы правы: компилятор узнает о возможности оптимизации вашего кода и чаще всего заменяет обычный String.concat на StringBuilder, но не всегда. Вы не можете полагаться на компилятор. Если код является сложным, компилятор может упустить возможность оптимизации. Если бы я был вами, я бы решил сделать мой код немного менее читаемым ради оптимизации. – cldjr

2

Это зависит от случая, но StringBuilder считается немного быстрее. Если вы выполняете конкатенацию внутри цикла, я бы предложил вам использовать StringBuilder.

В любом случае, я бы посоветовал вам профилировать и сравнивать ваш код (если вы делаете такое массивное приложение).

Будьте осторожны: экземпляры StringBuilder являются изменяемыми и не должны делиться между потоками (если вы действительно не знаете, что делаете.), В отличие от String, которые являются неизменяемыми.

+0

Переписал вопрос. Я знаю, что вы сказали, я имею в виду, что я должен писать? – Soyuz

+0

На самом деле должно быть какое-то подтверждение или источник для резервного копирования: «StringBuilder считается немного быстрее». Я предполагаю, что это из-за отсутствия накладных расходов синхронизации, но все же - источники были бы хороши. –

3

Ключевая фраза в вашем вопросе - «предположительно медленнее». Вам нужно определить, действительно ли это узкое место, а затем посмотреть, что быстрее.

Если вы собираетесь написать этот код, но еще не записали его, напишите вам, что бы яснее, а затем, если это необходимо, посмотрите, является ли это узким местом.

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

+0

На самом деле, после (просто) переписывания кода в обоих направлениях, мало различий в удобочитаемости, поскольку он просто меняет объявления класса и превращает concat() в append(). Думаю, я буду придерживаться StringBuilder для обеспечения производительности. – Soyuz

Смежные вопросы