Предположим, есть строка, мы выполним множество операций сращивания циклов с этой строкой, использование «+» позволит получить самую низкую производительность. Но насколько плоха эта производительность? Каким будет результат, если мы также добавим в тест производительности StringBuffer, StringBuilder или String.concat()? Эта статья даст ответ на эти вопросы!
Мы будем использовать Per4j для расчета производительности, поскольку этот инструмент может предоставить нам полный набор показателей производительности, таких как минимальное и максимальное затраченное время, стандартное отклонение статистического периода времени и т. д. В тестовом коде, чтобы получить точное значение стандартного отклонения, мы выполним тест 20 сращиваний «*» 50 000 раз. Вот метод, который мы будем использовать для объединения строк:
Скопируйте код кода следующим образом:
Оператор конкатенации (+)
Метод объединения строк concat(String str)
Метод добавления StringBuffer присоединить (String str)
Метод добавления StringBuilder add(String str)
Наконец, мы посмотрим на байт-код, чтобы увидеть, как именно выполняются эти методы. Теперь давайте начнем с создания нашего класса. Обратите внимание, что для расчета производительности каждого цикла каждый тестовый код в коде должен быть обернут библиотекой Per4J. Сначала определяем количество итераций
Скопируйте код кода следующим образом:
частный статический окончательный int OUTER_ITERATION = 20;
частный статический финал int INNER_ITERATION = 50000;
Далее мы будем использовать вышеуказанные 4 метода для реализации нашего тестового кода.
Скопируйте код кода следующим образом:
Строка addTestStr = "";
Строка concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;
for (int externalIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = новый LoggingStopWatch("StringAddConcat");
addTestStr = "";
for (int InternalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
addTestStr += "*";
стопВатч.стоп();
}
for (int externalIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = новый LoggingStopWatch("StringConcat");
concatTestStr = "";
for (int InternalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestStr.concat("*");
стопВатч.стоп();
}
for (int externalIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = новый LoggingStopWatch("StringBufferConcat");
concatTestSb = новый StringBuffer();
for (int InternalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
стопВатч.стоп();
}
for (int externalIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = новый LoggingStopWatch("StringBuilderConcat");
concatTestSbu = новый StringBuilder();
for (int InternalIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
стопВатч.стоп();
}
Затем запустите программу для получения показателей производительности. Моя операционная среда — 64-разрядная операционная система Windows 7, 32-разрядная машина JVM (7 ea) с 4 ГБ памяти и двухъядерным процессором Quad 2,00 ГГц.
Получилось идеально так, как мы себе представляли. Единственное, что интересно, так это то, почему String.concat еще и очень хорош. Мы все знаем, что String — это константный класс (класс, который не меняется после инициализации), так почему же производительность concat выше? (Примечание переводчика: на самом деле существует проблема с тестовым кодом оригинального автора. Тестовый код для метода concat() должен быть записан как concatTestStr=concatTestStr.concat(“*”).) Чтобы ответить на этот вопрос, вопрос, нам следует посмотреть декомпиляцию concat. Выходит байт-код. Пакет загрузки этой статьи содержит все байт-коды, но теперь давайте посмотрим на этот фрагмент кода concat:
Скопируйте код кода следующим образом:
46: новый #6; //класс java/lang/StringBuilder;
49: дуп
50: вызвать специальный #7 //Метод java/lang/StringBuilder."<init>":()V;
53: загрузка_1
54: вызвать виртуальный #8; //Метод java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: ldc #9 //Строка *;
59: вызвать виртуальный #8; //Метод java/lang/StringBuilder.append:
(Льява/язык/String;)Лява/язык/StringBuilder;
62: вызвать виртуальный #10 //Метод java/lang/StringBuilder.toString:();
Льява/язык/строка;
65: astore_1
66: ивк 7, 1
69: перейти к 38
Этот код является байт-кодом String.concat(). Из этого кода мы ясно видим, что метод concat() использует StringBuilder. Производительность concat() должна быть такой же хорошей, как и у StringBuilder, но из-за дополнительного создания StringBuilder и выполнение операции .append(str).append(str).toString() повлияет на производительность объединения, поэтому StringBuilder и String Времена канкате — 1,8 и 3,3.
Поэтому даже при выполнении простейшей конкатенации, если мы не хотим создавать экземпляр StringBuffer или StringBuilder, нам следует использовать concat. Но для большого количества операций сращивания строк не следует использовать concat (Примечание переводчика: поскольку тестовый код не полностью эквивалентен по функциям, среднее время обработки concat в замененном тестовом коде составляет 1650,9 миллисекунды. Этот результат находится в исходный текстовый комментарий), поскольку concat снизит производительность вашей программы и загрузит ваш процессор. Поэтому, чтобы получить максимальную производительность без учета потокобезопасности и синхронизации, нам следует попробовать использовать StringBuilder.