Лучше ли использовать String.format над строкой Concatenation в Java?

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

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

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

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

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

Ответ 1

Я бы предположил, что лучше использовать 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)

Ответ 2

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

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.format.

Ответ 3

Поскольку есть дискуссия о производительности, я подумал, что добавлю в сравнение, включающее 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 INFO [TestMain] - Формат = 1416 миллисекунд
  • 2012-01-11 16: 30: 46,190 INFO [TestMain] - Конкатенация = 134 миллисекунды
  • 2012-01-11 16: 30: 46,313 INFO [TestMain] - String Builder = 117 миллисекунд

Ответ 4

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

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

Ответ 5

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

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

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

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

Ответ 6

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

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

Ответ 7

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

файл: 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

Ответ 8

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

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

Ответ 9

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

  • Он не кодирует строку, которая будет построена локально.
  • Процесс сборки закодирован в строке.

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

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

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

Ответ 10

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

Однако конкатенация менее полезна и труднее читать. Как всегда, стоит сделать тест на свой код, чтобы узнать, что лучше. Различия могут быть незначительными в серверном приложении после того, как ваши пакеты ресурсов, локали и т.д. Загрузятся в память, а код - JITted.

Возможно, в качестве лучшей практики было бы неплохо создать собственный Formatter с соответствующим размером StringBuilder (Appendable) и Locale и использовать его, если вам нужно много форматирования.

Ответ 11

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

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

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

Ответ 12

Вы не можете сравнивать String Concatenation и String.Format с помощью указанной выше программы.

Вы можете попробовать это также изменить позицию использования вашего String.Format и Concatenation в вашем блоке кода, как показано ниже

public static void main(String[] args) throws Exception {      
  long start = System.currentTimeMillis();

  for( int i=0;i<1000000; i++){
    String s = String.format( "Hi %s; Hi to you %s",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") ;
}

Вы будете удивлены, увидев, что формат работает быстрее здесь. Это происходит потому, что созданные объекты intial могут не быть выпущены, и может возникнуть проблема с распределением памяти и, следовательно, с производительностью.

Ответ 13

Требуется немного времени, чтобы привыкнуть к String.Format, но в большинстве случаев оно того стоит. В мире NRA (никогда ничего не повторяйте) чрезвычайно полезно хранить ваши токенизированные сообщения (ведение журнала или пользователя) в библиотеке констант (я предпочитаю то, что равно статическому классу) и при необходимости вызывать их с помощью String.Format независимо от того, используете ли вы локализуются или нет. Попытки использовать такую библиотеку с методом конкатенации труднее читать, устранять неполадки, корректировать и управлять любым подходом, требующим конкатенации. Замена есть вариант, но я сомневаюсь в этом. После многих лет использования моя самая большая проблема с String.Format заключается в том, что длительность вызова неудобно велика, когда я передаю его в другую функцию (например, Msg), но ее легко обойти с помощью пользовательской функции, служащей псевдонимом.,