Czy lepiej jest używać Sznurka.formatowanie nad Konkatenacją łańcuchów w Javie?

Czy istnieje zauważalna różnica między używaniem String.Format a konkatenacją łańcuchów w Javie?

Zazwyczaj używam String.format ale czasami poślizgnę się i użyję konkat. Zastanawiałem się, czy jeden jest lepszy od drugiego.

Tak jak ja to widzę, String.Format daje więcej mocy w "formatowaniu" ciągu; A konkatenacja oznacza, że nie musisz się martwić o przypadkowe dodanie dodatkowego % s lub pominięcie jednego.

String.format jest również krótszy.

Który z nich jest bardziej czytelny zależy jak działa Twoja głowa.

Author: Sildoreth, 2009-05-29

12 answers

Sugerowałbym, że lepiej jest używać String.format(). Głównym powodem jest to, że String.format() może być łatwiej zlokalizowane za pomocą tekstu załadowanego z plików zasobów, podczas gdy konkatenacja nie może być zlokalizowana bez wytworzenia nowego pliku wykonywalnego z innym kodem dla każdego języka.

Jeśli planujesz, że Twoja aplikacja będzie możliwa do zlokalizowania, powinieneś również mieć zwyczaj określania pozycji argumentów dla tokenów formatu:

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

To może być zlokalizowane i mieć nazwę i czas tokeny wymieniane bez konieczności rekompilacji pliku wykonywalnego w celu uwzględnienia różnych zamówień. W przypadku pozycji argumentów można również ponownie użyć tego samego argumentu bez dwukrotnego przekazywania go do funkcji:

String.format("Hello %1$s, your name is %1$s and the time is %2$t", name, time)
 196
Author: workmad3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 17:27:17

O wydajności:

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");
}

Wyniki czasowe są następujące:

  • konkatenacja = 265 milisekundy
  • Format = 4141 milisekunda

Dlatego konkatenacja jest znacznie szybsza niż ciąg.format.

 125
Author: Icaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-22 23:25:00

Ponieważ jest dyskusja na temat wydajności, pomyślałem, że dodam do porównania, które obejmowało StringBuilder. Jest w rzeczywistości szybszy niż concat i, oczywiście, struna.opcja formatowania.

Aby zrobić to coś w rodzaju porównania jabłek do jabłek, tworzę instancję nowego Stringbuildera w pętli, a nie na zewnątrz (jest to w rzeczywistości szybsze niż robienie tylko jednej instancji, najprawdopodobniej ze względu na narzut realokacji miejsca dla pętli na końcu jednego z nich budowniczy).

    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] - Format = 1416 milisekunda
  • 2012-01-11 16:30:46,190 INFO [TestMain] - konkatenacja = 134 milisekunda
  • 2012-01-11 16:30:46,313 INFO [TestMain] - String Builder = 117 milisekunda
 35
Author: TechTrip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 22:47:02

Problem z .format polega na tym, że tracisz bezpieczeństwo typu statycznego. Możesz mieć zbyt mało argumentów dla swojego formatu i możesz mieć niewłaściwe typy dla specyfikatorów formatu - oba prowadzą do IllegalFormatException w czasie wykonywania , więc możesz skończyć z kodem logowania, który przerywa produkcję.

Natomiast argumenty + mogą być testowane przez kompilator.

 28
Author: Martin Schröder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-23 21:52:29

Który z nich jest bardziej czytelny zależy od tego, jak działa Twoja głowa.

Tu masz swoją odpowiedź. To kwestia gustu.

Konkatenacja łańcuchów jest nieznacznie szybsza, jak sądzę, ale to powinno być znikome.

 14
Author: Thilo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-29 10:56:49

Oto test z wieloma rozmiarami próbek w milisekundach.

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
 13
Author: Derek Ziemba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-22 07:06:41

Oto ten sam test jak wyżej z modyfikacją wywołania toString() metoda Na Stringbuilderze . Poniższe wyniki pokazują, że podejście StringBuilder jest nieco wolniejsze niż łączenie łańcuchów za pomocą + centrala.

Plik: StringTest.JPG / StringTestjava

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");

  }
}

polecenia powłoki: (skompiluj i uruchom StringTest 5 razy)

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

Wyniki :

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
 9
Author: Akos Cz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 21:29:33

String.format() to coś więcej niż tylko łączenie strun. Na przykład, możesz wyświetlać liczby w określonych lokalizacjach za pomocą String.format().

Jeśli jednak nie zależy ci na lokalizacji, nie ma żadnej różnicy funkcjonalnej. Może jeden jest szybszy od drugiego, ale w większości przypadków będzie znikomy..

 6
Author: Fortega,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-28 15:48:10

Nie zrobiłem żadnych konkretnych benchmarków, ale myślę, że konkatenacja może być szybsza. Sznurek.format() tworzy nowy program formatujący, który z kolei tworzy nowy StringBuilder (o rozmiarze tylko 16 znaków). To spora ilość narzutu, zwłaszcza jeśli formatujesz dłuższy ciąg, a StringBuilder musi zmieniać rozmiar.

Jednak konkatenacja jest mniej użyteczna i trudniejsza do odczytania. Jak zawsze, warto zrobić benchmark na swoim kodzie, aby zobaczyć, który jest lepszy. Na różnice mogą być znikome w aplikacji serwera po pakietach zasobów, lokalizacjach itp. są ładowane do pamięci i Kod jest JITted.

Być może jako najlepsza praktyka, dobrym pomysłem byłoby stworzenie własnego Formatera z odpowiednio dobranym Stringbuilderem (Appendable) i Locale i użycie tego, jeśli masz dużo formatowania do zrobienia.

 2
Author: AngerClown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-29 14:55:43

Może być zauważalna różnica.

String.format jest dość złożony i używa wyrażenia regularnego pod spodem, więc nie rób z tego nawyku używać go wszędzie, ale tylko tam, gdzie go potrzebujesz.

StringBuilder byłoby o rząd wielkości szybciej (jak ktoś tutaj już wskazał).

 2
Author: Pawel Zieminski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-10 08:19:55

Ogólnie rzecz biorąc, konkatenacja łańcuchów powinna być preferowana zamiast String.format. Ten ostatni ma dwie główne wady:

  1. nie koduje łańcucha znaków, który ma być zbudowany w sposób lokalny.
  2. proces budowania jest zakodowany w łańcuchu znaków.

Przez punkt 1 mam na myśli, że nie można zrozumieć, co robi String.format() wywołanie w jednym sekwencyjnym przejściu. Jeden jest zmuszony do przechodzenia tam iz powrotem między łańcuchem formatu a argumentami, podczas liczenia pozycji argumentów. W przypadku krótkich konkatenacji nie jest to zbyt duży problem. W tych przypadkach jednak konkatenacja łańcuchów jest mniej wyrazista.

Przez punkt 2 mam na myśli, że ważna część procesu budowania jest zakodowana w formacie string (za pomocą DSL). Używanie ciągów znaków do reprezentowania kodu ma wiele wad. Nie jest z natury bezpieczny dla typu i komplikuje podświetlanie składni, analizę kodu, optymalizację itp.

Oczywiście przy użyciu narzędzi lub frameworków zewnętrznych do języka Java, w grę mogą wchodzić nowe czynniki.

 1
Author: Stephane Bersier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-02 13:41:12

Nie można porównywać konkatenacji łańcuchów i łańcuchów łańcuchowych.Formatowania według programu powyżej.

Możesz spróbować również zmienić pozycję używanego ciągu.Formatowanie i konkatenacja w bloku kodu jak poniżej

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") ;
}

Będziesz zaskoczony, widząc, że Format działa tutaj szybciej. Dzieje się tak, ponieważ utworzone obiekty intialne mogą nie zostać zwolnione i może wystąpić problem z alokacją pamięci, a tym samym wydajnością.

 0
Author: DotNetUser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-29 04:37:35