Frage

Gibt es einen spürbaren Unterschied zwischen der Verwendung? String.format und String-Verkettung in Java?

Ich neige dazu, zu verwenden String.format aber gelegentlich rutscht es ab und es kommt zu einer Verkettung.Ich habe mich gefragt, ob einer besser ist als der andere.

Wie ich es sehe, String.format gibt Ihnen mehr Möglichkeiten beim „Formatieren“ der Zeichenfolge;und die Verkettung bedeutet, dass Sie sich keine Sorgen machen müssen, versehentlich ein zusätzliches %s einzufügen oder eines zu verpassen.

String.format ist auch kürzer.

Welche besser lesbar ist, hängt davon ab, wie Ihr Kopf funktioniert.

War es hilfreich?

Lösung

Ich würde vorschlagen, dass es besser Praxis String.format() zu bedienen ist. Der Hauptgrund ist, dass String.format() kann leichter mit von Ressourcendateien geladen Text lokalisiert werden, während Verkettung nicht ohne Erzeugung eines neuen ausführbaren mit unterschiedlichen Code für jede Sprache lokalisiert werden kann.

Wenn Sie auf Ihre Anwendung ist lokalisierbar Sie auch in die Gewohnheit der Angabe Argument Positionen für Ihre Format-Token als auch bekommen sollte:

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

Dies kann dann den Namen lokalisiert und haben werden und Zeit Token getauscht, ohne eine erneute Kompilierung der ausführbaren Datei zu benötigen für die andere Ordnung zu berücksichtigen. Mit Argument Positionen können Sie auch das gleiche Argument wiederverwenden, ohne sie in die Funktion übergeben zweimal:

String.format("Hello %1$s, your name is %1$s and the time is %2$t", name, time)

Andere Tipps

Über Performance:

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

Die Zeit Ergebnisse sind wie folgt:

  • Verkettungs = 265 ms
  • Format = 4141 Millisekunde

Daher Verkettung ist viel schneller als String.format.

Da es eine Diskussion über die Leistung ist, ich dachte ich, in einem Vergleich hinzufügen würde, die Stringbuilder enthalten. Es ist in der Tat schneller als die concat und natürlich die String.format Option.

Um dies eine Art von Äpfel mit Äpfeln vergleichen mache ich einen neuen String in der Schleife instanziiert eher außerhalb als (dies ist tatsächlich schneller als die meisten nur eine Instanziierung tun wahrscheinlich aufgrund der Overhead der Neuzuteilung Platz für den Looping anhängen an das Ende eines Builder).

    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 Millisekunde
  • 2012-01-11 16: 30: 46.190 INFO [TestMain] - Verkettungs = 134 ms
  • 2012-01-11 16: 30: 46.313 INFO [TestMain] - String Builder = 117 ms

Ein Problem bei .format ist, dass Sie statische Typsicherheit verlieren. Sie können für Ihr Format zu wenige Argumente haben, und Sie können die falschen Typen für den Formatbezeich haben -. Sowohl zu einem IllegalFormatException führenden zur Laufzeit , so dass Sie mit der Protokollierung Code, die Produktion bricht am Ende vielleicht

Im Gegensatz dazu können die Argumente + vom Compiler getestet werden.

  

Welche ist besser lesbar hängt davon ab, wie Sie Ihren Kopf arbeitet.

Sie haben Ihre Antwort recht.

Es ist eine Frage des persönlichen Geschmacks.

String-Verkettung ist geringfügig schneller, nehme ich an, aber das sollte vernachlässigbar sein.

Hier ist ein Test mit mehreren Probengrößen in Millisekunden.

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

Hier ist der gleiche Test wie oben mit der Änderung des Aufrufs der toString () Methode auf dem String . Die nachstehenden Ergebnisse zeigen, dass der String Ansatz ist nur ein bisschen langsamer als String-Verkettung mit dem + Operator.

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

  }
}

Shell-Befehle: (kompilieren und StringTest 5 Mal ausgeführt wird)

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

Ergebnisse:

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

String.format() ist mehr als nur verketten Saiten. Zum Beispiel können Sie Zahlen in einer bestimmten Gebietsschema mit String.format() angezeigt werden soll.

Wenn Sie jedoch nicht über die Lokalisierung kümmern, gibt es keinen funktionalen Unterschied. Vielleicht ist das eine ist schneller als die anderen, aber in den meisten Fällen wird es vernachlässigbar sein ..

Im Allgemeinen String-Verkettung sollte über String.format bevorzugt werden. Letzteres hat zwei wesentliche Nachteile:

  1. Es ist kodieren nicht die Zeichenfolge in einer lokalen Weise gebaut werden.
  2. Der Bauprozess wird in einem String codiert werden.

Mit dem Punkt 1, ich meine, dass es nicht möglich ist, zu verstehen, was ein String.format() Anruf wird in einem einzigen sequentiellen Durchgang zu tun. Man ist gezwungen hin und her zwischen dem Format-String und den Argumenten zu gehen, während die Position der Argumente zählen. Für kurze Verkettungen, dann ist dies ein Problem, nicht viel. In diesen Fällen ist jedoch die String-Verkettung weniger ausführlich.

Mit dem Punkt 2, dann meine ich, dass der wichtige Teil des Bauprozesses in der Format-String codiert wird, (unter Verwendung eines DSL). Strings Code zu vertreten hat viele Nachteile. Es ist nicht von Natur aus typsicher, und kompliziert Syntax-Hervorhebung, Code-Analyse, Optimierung, etc.

Natürlich, wenn Tools oder Frameworks außerhalb der Java-Sprache, neue Faktoren ins Spiel kommen können.

Ich habe keine spezifische Benchmarks getan, aber ich würde denken, dass Verkettung schneller sein kann. String.format () erzeugt ein neues Formatter was wiederum einen neuen String (mit einer Größe von nur 16 Zeichen) erzeugt. Das ist eine ganze Menge Aufwand vor allem, wenn Sie eine längere Zeichenfolge formatieren und String hält mit ändern.

Allerdings Verkettung ist weniger nützlich und schwieriger zu lesen. Wie immer, es lohnt sich, einen Benchmark auf Ihren Code zu tun, um zu sehen, was besser ist. Die Unterschiede in der Server-Anwendung nach dem Ressourcenbündel, Lokale usw. geladen werden im Speicher und der Code ist JITted vernachlässigbar sein.

Vielleicht als Best Practice, wäre es eine gute Idee zu sein, eigenen Formatter zu schaffen, mit einem richtigen Größe Stringbuilder (Appendable) und Locale und verwendet, wenn Sie eine Menge Formatierung zu tun haben.

Es kann ein merklicher Unterschied sein.

String.format ist recht komplex und verwendet einen regulären Ausdruck unter, so macht es nicht zur Gewohnheit, es überall zu verwenden, aber nur dort, wo Sie sie brauchen.

StringBuilder wäre eine Größenordnung schneller sein (wie jemand hier bereits darauf hingewiesen).

Sie können nicht vergleichen String Concatenation und String.Format durch das Programm oben.

Sie können versuchen, diese auch die Position werden Vertauschen Ihrer String.Format und Verkettungs im Code-Block wie unten mit

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

Sie werden überrascht sein, dass Format zu sehen, schneller hier funktioniert. Dies ist, da die intial Objekte erstellt nicht freigegeben werden kann, und es kann ein Problem mit Speicherzuweisung und damit die Leistung sein.

Es dauert ein wenig, sich an String.Format zu gewöhnen, aber es lohnt sich in den meisten Fällen.In der Welt von NRA (niemals etwas wiederholen) ist es äußerst nützlich, Ihre tokenisierten Nachrichten (Protokollierung oder Benutzer) in einer Konstantenbibliothek (ich bevorzuge eine statische Klasse) aufzubewahren und sie bei Bedarf mit String.Format aufzurufen, unabhängig davon, ob Sie lokalisieren oder nicht.Der Versuch, eine solche Bibliothek mit einer Verkettungsmethode zu verwenden, ist bei jedem Ansatz, der eine Verkettung erfordert, schwieriger zu lesen, Fehler zu beheben, Korrektur zu lesen und zu verwalten.Ein Austausch ist eine Option, aber ich bezweifle, dass er leistungsfähig ist.Nach Jahren der Verwendung besteht mein größtes Problem mit String.Format darin, dass der Aufruf unpraktisch lang ist, wenn ich ihn an eine andere Funktion (wie Msg) übergebe, aber das lässt sich mit einer benutzerdefinierten Funktion, die als Alias ​​dient, leicht umgehen .

Ich denke, wir mit MessageFormat.format gehen können, wie es auf den beiden Lesbarkeit und auch Performance-Aspekte sollte gut sein.

habe ich das gleiche Programm, das man verwendet, von Icaro in seiner obenen Antwort und ich verbessern es mit dem Code angehängt für die Verwendung von MessageFormat die Performance-Zahlen zu erklären.

  public static void main(String[] args) {
    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");

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

Verkettungs = 69 Millisekunden

     

Format = 1435 Millisekunde

     

Message = 200 ms

UPDATES:

Wie pro SonarLint Report, Printf-style-Format-Strings richtig sein sollte (Tintenfisch: S3457)

Da printf-Stil Format-Strings zur Laufzeit interpretiert werden, anstatt durch den Compiler validiert, können sie Fehler enthalten, die in den falschen Saiten führen geschaffen. Diese Regel überprüft statisch die Korrelation von printf-Stil Format-Strings, um ihre Argumente beim Aufruf der Format (...) Methoden der java.util.Formatter, java.lang.String, java.io.PrintStream, Message und java.io .PrintWriter Klassen und die printf (...) Methoden der java.io.PrintStream oder java.io.PrintWriter Klassen.

Ich ersetze den printf-Stil mit den geschweiften Klammern und ich habe wie unten interessante Ergebnisse etwas.

  

Verkettungs = 69 Millisekunden
Format = 1107 Millisekunde
   Format: geschweiften Klammern = 416 Millisekunde
Message = 215   Millisekunden
Message: geschweiften Klammern = 2517 Millisekunde

Mein Fazit:
Wie ich oben hervorgehoben, String.format mit geschweiften Klammern sollte eine gute Wahl sein, um Vorteile der guten Lesbarkeit und auch Leistung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top