Подтвердить что ты не робот

Производительность: 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?

4b9b3361

Ответ 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;
    }
}