Лучше ли использовать String.format поверх конкатенации строк в Java? - PullRequest
238 голосов
/ 29 мая 2009

Есть ли ощутимая разница между использованием String.format и конкатенацией строк в Java?

Я склонен использовать String.format, но иногда проскальзываю и использую конкатенацию. Мне было интересно, был ли один лучше другого.

На мой взгляд, String.format дает вам больше возможностей для "форматирования" строки; и конкатенация означает, что вам не нужно беспокоиться о случайном добавлении% s или об отсутствии.

String.format также короче.

Какой из них более читабелен, зависит от того, как работает ваша голова.

Ответы [ 14 ]

218 голосов
/ 29 мая 2009

Я бы предположил, что лучше использовать String.format(). Основная причина в том, что String.format() может быть легче локализовано с текстом, загруженным из файлов ресурсов, тогда как конкатенация не может быть локализована без создания нового исполняемого файла с различным кодом для каждого языка.

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

"Hello %1$s the time is %2$t"

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

String.format("Hello %1$s, your name is %1$s and the time is %2$t", name, time)
146 голосов
/ 18 января 2010

О производительности:

public static void main(String[] args) throws Exception {      
  long start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
    String s = "Hi " + i + "; Hi to you " + i*2;
  }
  long end = System.currentTimeMillis();
  System.out.println("Concatenation = " + ((end - start)) + " millisecond") ;

  start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
    String s = String.format("Hi %s; Hi to you %s",i, + i*2);
  }
  end = System.currentTimeMillis();
  System.out.println("Format = " + ((end - start)) + " millisecond");
}

Результаты синхронизации следующие:

  • Конкатенация = 265 миллисекунд
  • Формат = 4141 миллисекунда

Следовательно, конкатенация намного быстрее, чем формат String.

36 голосов
/ 12 января 2012

Так как есть обсуждение производительности, которое я решил добавить в сравнение, включающее StringBuilder. Это на самом деле быстрее, чем concat и, естественно, опция String.format.

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

    String formatString = "Hi %s; Hi to you %s";

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s = String.format(formatString, i, +i * 2);
    }

    long end = System.currentTimeMillis();
    log.info("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        String s = "Hi " + i + "; Hi to you " + i * 2;
    }

    end = System.currentTimeMillis();

    log.info("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        StringBuilder bldString = new StringBuilder("Hi ");
        bldString.append(i).append("; Hi to you ").append(i * 2);
    }

    end = System.currentTimeMillis();

    log.info("String Builder = " + ((end - start)) + " millisecond");
  • 2012-01-11 16: 30: 46,058 ИНФОРМАЦИЯ [TestMain] - Формат = 1416 миллисекунд
  • 2012-01-11 16: 30: 46,990 INFO [TestMain] - Конкатенация = 134 миллисекунды
  • 2012-01-11 16: 30: 46,313 ИНФОРМАЦИЯ [TestMain] - String Builder = 117 миллисекунд
34 голосов
/ 23 февраля 2012

Одна проблема с .format заключается в том, что вы теряете безопасность статического типа. У вас может быть слишком мало аргументов для вашего формата, и у вас могут быть неправильные типы для спецификаторов формата - оба приводят к IllegalFormatException во время выполнения , так что вы можете в конечном итоге получить код, который нарушает работу.

Напротив, аргументы + могут быть проверены компилятором.

17 голосов
/ 29 мая 2009

Какой из них более читабелен, зависит от того, как работает ваша голова.

Вы получили свой ответ прямо там.

Это вопрос личного вкуса.

Я полагаю, что сцепление строк незначительно быстрее, но это должно быть незначительным.

14 голосов
/ 22 октября 2014

Вот тест с несколькими размерами выборки в миллисекундах.

public class Time {

public static String sysFile = "/sys/class/camera/rear/rear_flash";
public static String cmdString = "echo %s > " + sysFile;

public static void main(String[] args) {

  int i = 1;
  for(int run=1; run <= 12; run++){
      for(int test =1; test <= 2 ; test++){
        System.out.println(
                String.format("\nTEST: %s, RUN: %s, Iterations: %s",run,test,i));
        test(run, i);
      }
      System.out.println("\n____________________________");
      i = i*3;
  }
}

public static void test(int run, int iterations){

      long start = System.nanoTime();
      for( int i=0;i<iterations; i++){
          String s = "echo " + i + " > "+ sysFile;
      }
      long t = System.nanoTime() - start;   
      String r = String.format("  %-13s =%10d %s", "Concatenation",t,"nanosecond");
      System.out.println(r) ;


     start = System.nanoTime();       
     for( int i=0;i<iterations; i++){
         String s =  String.format(cmdString, i);
     }
     t = System.nanoTime() - start; 
     r = String.format("  %-13s =%10d %s", "Format",t,"nanosecond");
     System.out.println(r);

      start = System.nanoTime();          
      for( int i=0;i<iterations; i++){
          StringBuilder b = new StringBuilder("echo ");
          b.append(i).append(" > ").append(sysFile);
          String s = b.toString();
      }
     t = System.nanoTime() - start; 
     r = String.format("  %-13s =%10d %s", "StringBuilder",t,"nanosecond");
     System.out.println(r);
}

}

TEST: 1, RUN: 1, Iterations: 1
  Concatenation =     14911 nanosecond
  Format        =     45026 nanosecond
  StringBuilder =      3509 nanosecond

TEST: 1, RUN: 2, Iterations: 1
  Concatenation =      3509 nanosecond
  Format        =     38594 nanosecond
  StringBuilder =      3509 nanosecond

____________________________

TEST: 2, RUN: 1, Iterations: 3
  Concatenation =      8479 nanosecond
  Format        =     94438 nanosecond
  StringBuilder =      5263 nanosecond

TEST: 2, RUN: 2, Iterations: 3
  Concatenation =      4970 nanosecond
  Format        =     92976 nanosecond
  StringBuilder =      5848 nanosecond

____________________________

TEST: 3, RUN: 1, Iterations: 9
  Concatenation =     11403 nanosecond
  Format        =    287115 nanosecond
  StringBuilder =     14326 nanosecond

TEST: 3, RUN: 2, Iterations: 9
  Concatenation =     12280 nanosecond
  Format        =    209051 nanosecond
  StringBuilder =     11818 nanosecond

____________________________

TEST: 5, RUN: 1, Iterations: 81
  Concatenation =     54383 nanosecond
  Format        =   1503113 nanosecond
  StringBuilder =     40056 nanosecond

TEST: 5, RUN: 2, Iterations: 81
  Concatenation =     44149 nanosecond
  Format        =   1264241 nanosecond
  StringBuilder =     34208 nanosecond

____________________________

TEST: 6, RUN: 1, Iterations: 243
  Concatenation =     76018 nanosecond
  Format        =   3210891 nanosecond
  StringBuilder =     76603 nanosecond

TEST: 6, RUN: 2, Iterations: 243
  Concatenation =     91222 nanosecond
  Format        =   2716773 nanosecond
  StringBuilder =     73972 nanosecond

____________________________

TEST: 8, RUN: 1, Iterations: 2187
  Concatenation =    527450 nanosecond
  Format        =  10291108 nanosecond
  StringBuilder =    885027 nanosecond

TEST: 8, RUN: 2, Iterations: 2187
  Concatenation =    526865 nanosecond
  Format        =   6294307 nanosecond
  StringBuilder =    591773 nanosecond

____________________________

TEST: 10, RUN: 1, Iterations: 19683
  Concatenation =   4592961 nanosecond
  Format        =  60114307 nanosecond
  StringBuilder =   2129387 nanosecond

TEST: 10, RUN: 2, Iterations: 19683
  Concatenation =   1850166 nanosecond
  Format        =  35940524 nanosecond
  StringBuilder =   1885544 nanosecond

  ____________________________

TEST: 12, RUN: 1, Iterations: 177147
  Concatenation =  26847286 nanosecond
  Format        = 126332877 nanosecond
  StringBuilder =  17578914 nanosecond

TEST: 12, RUN: 2, Iterations: 177147
  Concatenation =  24405056 nanosecond
  Format        = 129707207 nanosecond
  StringBuilder =  12253840 nanosecond
9 голосов
/ 04 декабря 2013

Это тот же тест, что и выше, с модификацией вызова метода toString () для StringBuilder . Приведенные ниже результаты показывают, что подход StringBuilder немного медленнее, чем конкатенация строк с использованием оператора + .

файл: StringTest.java

class StringTest {

  public static void main(String[] args) {

    String formatString = "Hi %s; Hi to you %s";

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s = String.format(formatString, i, +i * 2);
    }

    long end = System.currentTimeMillis();
    System.out.println("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        String s = "Hi " + i + "; Hi to you " + i * 2;
    }

    end = System.currentTimeMillis();

    System.out.println("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        StringBuilder bldString = new StringBuilder("Hi ");
        bldString.append(i).append("Hi to you ").append(i * 2).toString();
    }

    end = System.currentTimeMillis();

    System.out.println("String Builder = " + ((end - start)) + " millisecond");

  }
}

Команды оболочки: (скомпилируйте и запустите StringTest 5 раз)

> javac StringTest.java
> sh -c "for i in \$(seq 1 5); do echo \"Run \${i}\"; java StringTest; done"

Результаты:

Run 1
Format = 1290 millisecond
Concatenation = 115 millisecond
String Builder = 130 millisecond

Run 2
Format = 1265 millisecond
Concatenation = 114 millisecond
String Builder = 126 millisecond

Run 3
Format = 1303 millisecond
Concatenation = 114 millisecond
String Builder = 127 millisecond

Run 4
Format = 1297 millisecond
Concatenation = 114 millisecond
String Builder = 127 millisecond

Run 5
Format = 1270 millisecond
Concatenation = 114 millisecond
String Builder = 126 millisecond
6 голосов
/ 29 мая 2009

String.format() - это больше, чем просто конкатенация строк. Например, вы можете отображать числа в определенной локали, используя String.format().

Однако, если вас не волнует локализация, функциональных отличий нет. Может быть, один быстрее другого, но в большинстве случаев он будет незначительным ..

4 голосов
/ 02 января 2016

Как правило, конкатенация строк должна быть предпочтительнее, чем String.format. Последний имеет два основных недостатка:

  1. Не кодирует строку, которая будет построена локально.
  2. Процесс сборки кодируется в виде строки.

Под пунктом 1 я имею в виду, что невозможно понять, что делает вызов String.format() за один последовательный проход. Один вынужден переходить назад и вперед между строкой формата и аргументами при подсчете позиции аргументов. Для коротких конкатенаций это не большая проблема. Однако в этих случаях конкатенация строк менее многословна.

Под пунктом 2 я подразумеваю, что важная часть процесса сборки кодируется в строке формата (с использованием DSL). Использование строк для представления кода имеет много недостатков. Он не является безопасным по типу и усложняет подсветку синтаксиса, анализ кода, оптимизацию и т. Д.

Конечно, при использовании инструментов или платформ, внешних по отношению к языку Java, могут играть роль новые факторы.

2 голосов
/ 05 октября 2011

Там может быть ощутимая разница.

String.format довольно сложный и использует регулярное выражение внизу, поэтому не делайте это привычкой использовать его везде, но только там, где вам это нужно.

StringBuilder будет на порядок быстрее (как кто-то здесь уже указал).

...