Оператор конкатенации (+) против concat()
Для объединения строк мы можем использовать либо concat()
или оператор concat (+)
,
Я попробовал следующий тест производительности и нашел concat()
это более быстрый и эффективный способ объединения строк.
Сравнение конкатенации строк в 100 000 раз:
String str = null;
//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for(int i=0; i<100000; i++){
str = "Hi";
str = str+" Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();
long timetaken1 = time2-time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator :" + "Time taken =" + timetaken1 +
" Memory Consumed =" + memoryTaken1);
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for(int j=0; j<100000; j++){
str = "Hi";
str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4-time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method :" + "Time taken =" + timetaken2 +
" Memory Consumed =" + memoryTaken2);
Результат
Concat operator: Time taken = 31; Memory Consumed = 2259096
Concat method : Time taken = 16; Memory Consumed = 299592
Если concat()
быстрее, чем оператор, тогда когда мы должны использовать оператор конкатенации (+)
?
8 ответов
Метод concat всегда создает новую строку с результатом конкатенации.
Оператор плюс поддерживается созданием StringBuilder, добавляя все необходимые вам значения String и далее вызывая toString().
Поэтому, если вам нужно объединить два значения, лучше использовать concat(). Если вам нужно объединить 100 значений, вы должны использовать оператор плюс или явно использовать StringBuilder (например, в случае добавления в цикл).
На самом деле s1 + s2 и s1.concat(s2) очень разные.
s1 + s2 преобразуется с помощью javac в
(new StringBuilder(String.valueOf(s1)).append(s2).toString();
Вы можете увидеть это, если декомпилируете.class. Эта конструкция не очень эффективна; он включает до трех новых распределений char[] и три операции копирования char[].
s1.concat(s2) - это всегда одна новая char[] + одна операция копирования, см. String.java
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}
Обратите внимание, что new String(int, int, char[]) является закрытым конструктором пакета String. Он использует char buf[] напрямую, без обычного копирования, чтобы обеспечить невидимость buf для неизменности String.
Ваш тест должен выполняться не менее 2 секунд с каждым циклом в отдельном методе, чтобы иметь смысл. Короткие тесты могут быть каждый трудно воспроизвести и сравнить. Судя по вашему времени, вы используете Windows (то есть, потому что у вас 16 и 31 мс;) Вместо этого попробуйте System.nanoTime(). Когда ваш цикл повторяется более 10000 раз, весь метод компилируется. Это означает, что ваш более поздний метод уже скомпилирован при запуске.
В ответ на ваш вопрос concat незначительно быстрее при добавлении двух строк. Тем не менее, он идет с типизацией и концептуальными накладными расходами, которые, вероятно, будут намного больше, чем процессор, который вы экономите. Даже если ваши тесты повторяются 100 000 раз, это экономит менее 15 мс, и, тем не менее, это стоило вам гораздо больше, чем в ваше время (что, вероятно, будет стоить дороже), которое вы могли бы найти в будущей версии JVM, Разница оптимизируется всегда, и сложность вашего кода все еще там.
РЕДАКТИРОВАТЬ: я не заметил, что результат памяти был подозрительным.
String str = null;
//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 10000; i++) {
str = "Hi";
str = str + " Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();
long timetaken1 = time2 - time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + " Memory Consumed= " + memoryTaken1);
str = null;
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for (int j = 0; j < 10000; j++) {
str = "Hi";
str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4 - time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method :" + "Time taken =" + timetaken2 + " Memory Consumed= " + memoryTaken2);
печатает при запуске с -XX:-UseTLAB -mx1g
Concat operator :Time taken =12 Memory Consumed= 1291456
Concat method :Time taken =7 Memory Consumed= 560000
сделать соотношение использования памяти около 2:1. В исходном вопросе результат меняется каждый раз, когда вы его запускаете, иногда .concat()
Похоже, использовать больше.
Я верю, что "стиль" объединения будет иметь значение.
Для concat() он внутренне создает новый буфер массива char и возвращает новую строку на основе этого массива char.
Для оператора + компилятор фактически переводит его для использования StringBuffer/StringBuilder.
Поэтому, если вы объединяете две строки, concat() определенно является лучшим выбором, поскольку число созданных объектов является только строкой результата (и буфером символов, используемым внутри), при использовании +
Оператор будет переведен на:
result = strA + strB;
-- translate to -->
result = new StringBuilder(strA).append(strB).toString();
Создается дополнительный экземпляр StringBuilder.
Однако, если вы объединяете, например, пять строк подряд, каждая concat() создаст новый объект String. При использовании +
оператор, компилятор преобразует оператор в один StringBuilder с несколькими операциями добавления. Это определенно экономит много ненужных временных экземпляров объекта:
result = strA + strB + strC + strD + strE;
-- translate to -->
result = new StringBuilder(strA).append(strB).append(strC).append(strD).append(strE).toString();
Хотя и оператор, и метод выдают один и тот же вывод, способ их внутренней работы отличается.
concat()
метод, который просто объединяет str1 с str2 и выводит строку, более эффективен для небольшого числа конкатенаций.
Но с оператором конкатенации '+', str1+=str2
; будет интерпретироваться какstr1 = new StringBuilder().append(str1).append(str2).toString();
Вы можете использовать метод concat при использовании меньшего числа строк для конкатенации. Но метод StringBuilder будет быстрым с точки зрения производительности, если вы используете большое количество строк.
Вы всегда можете использовать +
если только вы используете>= Java 1.5 и не объявляете вашу базовую строку (которую вы хотите объединить) вне цикла. В Java 1.5 это приводит к созданию new StringBuilder
и работать над этим, пока ваша строка не будет завершена. Это самый быстрый способ.
В любом случае - если вы находитесь в цикле (и объединяете строки с +
) - каждая итерация цикла создает new StringBuilder
- это не лучшая идея. Так что это где вы должны заставить использование StringBuilder
или же StringBuffer
(потокобезопасные) классы.
Как правило, эта ссылка четко отвечает на ваш вопрос и дает вам полное знание:
http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/
В общем случае плохая практика объединять строки с +
и с concat()
, Если вы хотите создать строковое использование StringBuilder
вместо.
На самом деле, оба одинаковы. Если вы видите код concat(String paramString)
он возвратит новый строковый объект, и в операторе (+) он также сгенерирует новый строковый объект.
Если вы не хотите создавать новый объект, используйте построитель строк для объединения двух строк.