Производительность: Java String.format
Возможный дубликат:
Должен ли я использовать String.format() Java, если производительность важна?
Мне было интересно, хорошо ли использовать String.format
в Java-приложениях вместо StringBuilder
... поэтому просто напишу простой тест, например:
public static void main(String[] args) {
int i = 0;
Long start = System.currentTimeMillis();
while (i < 10000) {
String s = String.format("test %d", i);
i++;
}
System.out.println(System.currentTimeMillis() - start);
i = 0;
start = System.currentTimeMillis();
while (i < 10000) {
String s = new StringBuilder().append("test ").append(i).toString();
i++;
}
System.out.println(System.currentTimeMillis() - start);
}
И результаты, где:
238
15
Итак, если мой тест действителен, StringBuilder
быстрее, чем String.format
. ОК.
Теперь я начинаю думать, как работает String.format
. Является ли это простой конкатенацией строк, например "test " + i
?
Каковы различия между конкатенацией StringBuilder
и String.format
? Есть ли способ простой как String.format
и быстрый, как StringBuilder
?
Ответы
Ответ 1
Я написал быстрый caliper для сравнения String.format()
vs. StringBuilder
, StringBuffer
, normal String
+
, методы String.replace()
и String.concat()
:
public class StringFormatBenchmark extends SimpleBenchmark {
public void timeStringFormat(int reps) {
while (--reps >= 0) {
String s = String.format("test %d", reps);
}
}
public void timeStringBuilder(int reps) {
while (--reps >= 0) {
String s = new StringBuilder("test ").append(reps).toString();
}
}
public void timeStringBuffer(int reps) {
while (--reps >= 0) {
String s = new StringBuffer("test ").append(reps).toString();
}
}
public void timeStringPlusOperator(int reps) {
while (--reps >= 0) {
String s = "test " + reps;
}
}
public void timeReplace(int reps) {
while (--reps >= 0) {
String s = "test {}".replace("{}", String.valueOf(reps));
}
}
public void timeStringConcat(int reps) {
while (--reps >= 0) {
String s = "test ".concat(String.valueOf(reps));
}
}
public static void main(String[] args) {
new Runner().run(StringFormatBenchmark.class.getName());
}
}
Результаты следуют (Java 1.6.0_26-b03, Ubuntu, 32 бит):
![caliper2]()
Ясно, что String.format()
намного медленнее (на порядок). Кроме того, StringBuffer
значительно медленнее, чем StringBuilder
(как мы учили). Наконец, оператор StringBuilder
и String
+
почти идентичен, поскольку они компилируются в очень похожий байт-код. String.concat()
немного медленнее.
Также не используйте String.replace()
, если достаточно простого конкатенации.
Ответ 2
String.format относительно медленнее, но обычно более чем достаточно быстро.
Я бы использовал формат, если это проще, если только вы не видите проблему с производительностью при профилировании своего приложения.
Примечание. String.format в вашем примере принимает ~ 24 микросекунды и пока не будет полностью разогреваться. Я проигнорировал первые 10K итераций.
IMHO "test " + i
является самым простым в этом случае.
Ответ 3
Я запустил тестовое пост-JVM разминку (как только методы скомпилированы) и получить аналогичные результаты, при этом StringBuilder более чем на 30 раз быстрее.
Формат : 943
stringbuilder: 26
public class TestPerf {
private static int NUM_RUN;
public static void main(String[] args) {
NUM_RUN = 100_000;
//warm up
for (int i = 0; i < 10; i++) {
method1();
method2();
}
System.gc();
System.out.println("Starting");
long sum = 0;
long start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += method1();
}
long end = System.nanoTime();
System.out.println("format: " + (end - start) / 1000000);
System.gc();
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += method2();
}
end = System.nanoTime();
System.out.println("stringbuilder: " + (end - start) / 1000000);
System.out.println(sum);
}
private static int method1() {
int sum = 0;
for (int i = 0; i < NUM_RUN; i++) {
String s = String.format("test %d", i);
sum += s.length();
}
return sum;
}
private static int method2() {
int sum = 0;
for (int i = 0; i < NUM_RUN; i++) {
String s = new StringBuilder().append("test ").append(i).toString();
sum += s.length();
}
return sum;
}
}