Frage

Angesichts der 2 toString() Nachfolgend finden Sie die folgenden Implementierungen, welche bevorzugt wird:

public String toString(){
    return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}

oder

public String toString(){
    StringBuilder sb = new StringBuilder(100);
    return sb.append("{a:").append(a)
          .append(", b:").append(b)
          .append(", c:").append(c)
          .append("}")
          .toString();
}

?

Noch wichtiger ist, dass es angesichts der Tatsache, dass wir nur drei Eigenschaften haben, möglicherweise keinen Unterschied macht, aber von welchem ​​Punkt aus Sie wechseln würden + verknüpfen mit StringBuilder?

War es hilfreich?

Lösung

Version 1 ist vorzuziehen, da sie kürzer ist und Der Compiler wird es tatsächlich in Version 2 umwandeln - keinerlei Leistungsunterschied.

Noch wichtiger ist, da wir nur 3 Eigenschaften haben, kann es keinen Unterschied machen, aber an welchem ​​Punkt wechseln Sie von Concat zum Builder?

An dem Punkt, an dem Sie in einer Schleife verketten, kann der Compiler normalerweise nicht ersetzen StringBuilder von selbst.

Andere Tipps

Der Schlüssel liegt darin, ob Sie eine einzelne Verkettung an einem Ort schreiben oder sie im Laufe der Zeit ansammeln.

Für das von Ihnen angegebene Beispiel macht es keinen Sinn, StringBuilder explizit zu verwenden.(Sehen Sie sich den kompilierten Code für Ihren ersten Fall an.)

Wenn Sie jedoch eine Zeichenfolge erstellen, z.Verwenden Sie innerhalb einer Schleife StringBuilder.

Nehmen wir zur Verdeutlichung an, dass HugeArray Tausende von Zeichenfolgen enthält: Code wie folgt:

...
String result = "";
for (String s : hugeArray) {
    result = result + s;
}

ist sehr zeit- und speicherintensiv im Vergleich zu:

...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
    sb.append(s);
}
String result = sb.toString();

Ich bevorzuge:

String.format( "{a: %s, b: %s, c: %s}", a, b, c );

...weil es kurz und lesbar ist.

Ich würde nicht Optimieren Sie dies für die Geschwindigkeit, es sei denn, Sie verwenden es in einer Schleife mit einer sehr hohen Wiederholungszahl Und habe den Leistungsunterschied gemessen.

Ich stimme zu, dass dieses Formular verwirrend werden kann, wenn man viele Parameter ausgeben muss (wie es in einem der Kommentare heißt).In diesem Fall würde ich zu einer besser lesbaren Form wechseln (vielleicht mit ToStringBuilder von Apache-Commons - entnommen aus der Antwort von Matt b) und ignoriere die Leistung erneut.

In den meisten Fällen werden Sie keinen wirklichen Unterschied zwischen den beiden Ansätzen feststellen, aber es ist einfach, ein Worst-Case-Szenario wie dieses zu konstruieren:

public class Main
{
    public static void main(String[] args)
    {
        long now = System.currentTimeMillis();
        slow();
        System.out.println("slow elapsed " + (System.currentTimeMillis() - now) + " ms");

        now = System.currentTimeMillis();
        fast();
        System.out.println("fast elapsed " + (System.currentTimeMillis() - now) + " ms");
    }

    private static void fast()
    {
        StringBuilder s = new StringBuilder();
        for(int i=0;i<100000;i++)
            s.append("*");      
    }

    private static void slow()
    {
        String s = "";
        for(int i=0;i<100000;i++)
            s+="*";
    }
}

Die Ausgabe ist:

slow elapsed 11741 ms
fast elapsed 7 ms

Das Problem besteht darin, dass durch das Anhängen von += an eine Zeichenfolge eine neue Zeichenfolge rekonstruiert wird, sodass etwas kostet, das linear zur Länge Ihrer Zeichenfolgen (Summe aus beiden) ist.

Also - zu deiner Frage:

Der zweite Ansatz wäre schneller, aber weniger lesbar und schwieriger zu warten.Wie gesagt, in Ihrem speziellen Fall würden Sie den Unterschied wahrscheinlich nicht bemerken.

Ich hatte auch einen Konflikt mit meinem Chef darüber, ob ich append oder + verwenden sollte. Da sie Append verwenden (ich kann immer noch nicht herausfinden, wie es jedes Mal heißt, wenn ein neues Objekt erstellt wird).Deshalb dachte ich darüber nach, etwas Forschung und Entwicklung zu betreiben. Obwohl ich die Erklärungen von Michael Borgwardt liebe, wollte ich nur eine Erklärung zeigen, falls jemand es in Zukunft wirklich wissen muss.

/**
 *
 * @author Perilbrain
 */
public class Appc {
    public Appc() {
        String x = "no name";
        x += "I have Added a name" + "We May need few more names" + Appc.this;
        x.concat(x);
        // x+=x.toString(); --It creates new StringBuilder object before concatenation so avoid if possible
        //System.out.println(x);
    }

    public void Sb() {
        StringBuilder sbb = new StringBuilder("no name");
        sbb.append("I have Added a name");
        sbb.append("We May need few more names");
        sbb.append(Appc.this);
        sbb.append(sbb.toString());
        // System.out.println(sbb.toString());
    }
}

und die Demontage der oben genannten Klasse ergibt Folgendes:

 .method public <init>()V //public Appc()
  .limit stack 2
  .limit locals 2
met001_begin:                                  ; DATA XREF: met001_slot000i
  .line 12
    aload_0 ; met001_slot000
    invokespecial java/lang/Object.<init>()V
  .line 13
    ldc "no name"
    astore_1 ; met001_slot001
  .line 14

met001_7:                                      ; DATA XREF: met001_slot001i
    new java/lang/StringBuilder //1st object of SB
    dup
    invokespecial java/lang/StringBuilder.<init>()V
    aload_1 ; met001_slot001
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    ldc "I have Added a nameWe May need few more names"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    aload_0 ; met001_slot000
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
    invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
    astore_1 ; met001_slot001
  .line 15
    aload_1 ; met001_slot001
    aload_1 ; met001_slot001
    invokevirtual java/lang/String.concat(Ljava/lang/String;)Ljava/lang/Strin\
g;
    pop
  .line 18
    return //no more SB created
met001_end:                                    ; DATA XREF: met001_slot000i ...

; ===========================================================================

;met001_slot000                                ; DATA XREF: <init>r ...
    .var 0 is this LAppc; from met001_begin to met001_end
;met001_slot001                                ; DATA XREF: <init>+6w ...
    .var 1 is x Ljava/lang/String; from met001_7 to met001_end
  .end method
;44-1=44
; ---------------------------------------------------------------------------


; Segment type: Pure code
  .method public Sb()V //public void Sb
  .limit stack 3
  .limit locals 2
met002_begin:                                  ; DATA XREF: met002_slot000i
  .line 21
    new java/lang/StringBuilder
    dup
    ldc "no name"
    invokespecial java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    astore_1 ; met002_slot001
  .line 22

met002_10:                                     ; DATA XREF: met002_slot001i
    aload_1 ; met002_slot001
    ldc "I have Added a name"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 23
    aload_1 ; met002_slot001
    ldc "We May need few more names"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 24
    aload_1 ; met002_slot001
    aload_0 ; met002_slot000
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
    pop
  .line 25
    aload_1 ; met002_slot001
    aload_1 ; met002_slot001
    invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 28
    return
met002_end:                                    ; DATA XREF: met002_slot000i ...


;met002_slot000                                ; DATA XREF: Sb+25r
    .var 0 is this LAppc; from met002_begin to met002_end
;met002_slot001                                ; DATA XREF: Sb+9w ...
    .var 1 is sbb Ljava/lang/StringBuilder; from met002_10 to met002_end
  .end method
;96-49=48
; ---------------------------------------------------------------------------

Aus den beiden obigen Codes können Sie ersehen, dass Michael Recht hat. Es wird jeweils nur ein SB-Objekt erstellt.

Seit Java 1.5 generiert die einfache einzeilige Verkettung mit „+“ und StringBuilder.append() genau denselben Bytecode.

Um die Lesbarkeit des Codes zu gewährleisten, verwenden Sie daher „+“.

2 Ausnahmen:

  • Multithread-Umgebung:StringBuffer
  • Verkettung in Schleifen:StringBuilder/StringBuffer

Unter Verwendung der neuesten Version von Java(1.8) erfolgt die Disassemblierung(javap -c) zeigt die vom Compiler eingeführte Optimierung. + sowie sb.append() wird sehr ähnlichen Code generieren.Es lohnt sich jedoch, das Verhalten zu überprüfen, wenn wir es verwenden + in einer for-Schleife.

Hinzufügen von Zeichenfolgen mit + in einer for-Schleife

Java:

public String myCatPlus(String[] vals) {
    String result = "";
    for (String val : vals) {
        result = result + val;
    }
    return result;
}

ByteCode:(for Loop-Auszug)

12: iload         5
14: iload         4
16: if_icmpge     51
19: aload_3
20: iload         5
22: aaload
23: astore        6
25: new           #3                  // class java/lang/StringBuilder
28: dup
29: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
32: aload_2
33: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: aload         6
38: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: astore_2
45: iinc          5, 1
48: goto          12

Hinzufügen von Strings mit stringbuilder.append

Java:

public String myCatSb(String[] vals) {
    StringBuilder sb = new StringBuilder();
    for(String val : vals) {
        sb.append(val);
    }
    return sb.toString();
}

ByteCdoe:(for Loop-Auszug)

17: iload         5
19: iload         4
21: if_icmpge     43
24: aload_3
25: iload         5
27: aaload
28: astore        6
30: aload_2
31: aload         6
33: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: pop
37: iinc          5, 1
40: goto          17
43: aload_2

Es gibt ein bisschen eklatanter Unterschied obwohl.Im ersten Fall, wo + war gebraucht, neu StringBuilder wird für jede for-Schleifeniteration erstellt und das generierte Ergebnis wird durch Ausführen von a gespeichert toString() Anruf (29 bis 41).Sie generieren also Zwischenzeichenfolgen, die Sie bei der Verwendung wirklich nicht benötigen + Betreiber in for Schleife.

In Java 9 sollte die Version 1 schneller sein, da sie konvertiert wird invokedynamic Anruf.Weitere Details finden Sie in JEP-280:

Die Idee besteht darin, den gesamten StringBuilder-Anhängetanz durch einen einfachen invokedynamic-Aufruf an java.lang.invoke.StringConcatFactory zu ersetzen, der die Werte akzeptiert, die verkettet werden müssen.

Apache Commons-Lang hat eine ToStringBuilder Klasse, die super einfach zu bedienen ist.Es leistet gute Arbeit sowohl bei der Handhabung der Append-Logik als auch bei der Formatierung, wie Ihr toString aussehen soll.

public void toString() {
     ToStringBuilder tsb =  new ToStringBuilder(this);
     tsb.append("a", a);
     tsb.append("b", b)
     return tsb.toString();
}

Gibt eine Ausgabe zurück, die wie folgt aussieht com.blah.YourClass@abc1321f[a=whatever, b=foo].

Oder in einer komprimierteren Form durch Verkettung:

public void toString() {
     return new ToStringBuilder(this).append("a", a).append("b", b").toString();
}

Oder wenn Sie Reflektion verwenden möchten, um jedes Feld der Klasse einzubeziehen:

public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

Sie können bei Bedarf auch den Stil des ToStrings anpassen.

Aus Leistungsgründen ist die Verwendung von += (String Verkettung) wird nicht empfohlen.Der Grund dafür ist:Java String ist unveränderlich, jedes Mal, wenn eine neue Verkettung durchgeführt wird, wird eine neue durchgeführt String erstellt wird (das neue hat bereits einen anderen Fingerabdruck als das alte). im String-Pool ).Das Erstellen neuer Strings setzt den GC unter Druck und verlangsamt das Programm:Die Objekterstellung ist teuer.

Der folgende Code soll es gleichzeitig praktischer und klarer machen.

public static void main(String[] args) 
{
    // warming up
    for(int i = 0; i < 100; i++)
        RandomStringUtils.randomAlphanumeric(1024);
    final StringBuilder appender = new StringBuilder();
    for(int i = 0; i < 100; i++)
        appender.append(RandomStringUtils.randomAlphanumeric(i));

    // testing
    for(int i = 1; i <= 10000; i*=10)
        test(i);
}

public static void test(final int howMany) 
{
    List<String> samples = new ArrayList<>(howMany);
    for(int i = 0; i < howMany; i++)
        samples.add(RandomStringUtils.randomAlphabetic(128));

    final StringBuilder builder = new StringBuilder();
    long start = System.nanoTime();
    for(String sample: samples)
        builder.append(sample);
    builder.toString();
    long elapsed = System.nanoTime() - start;
    System.out.printf("builder - %d - elapsed: %dus\n", howMany, elapsed / 1000);

    String accumulator = "";
    start = System.nanoTime();
    for(String sample: samples)
        accumulator += sample;
    elapsed = System.nanoTime() - start;
    System.out.printf("concatenation - %d - elapsed: %dus\n", howMany, elapsed / (int) 1e3);

    start = System.nanoTime();
    String newOne = null;
    for(String sample: samples)
        newOne = new String(sample);
    elapsed = System.nanoTime() - start;
    System.out.printf("creation - %d - elapsed: %dus\n\n", howMany, elapsed / 1000);
}

Die Ergebnisse eines Laufs werden unten aufgeführt.

builder - 1 - elapsed: 132us
concatenation - 1 - elapsed: 4us
creation - 1 - elapsed: 5us

builder - 10 - elapsed: 9us
concatenation - 10 - elapsed: 26us
creation - 10 - elapsed: 5us

builder - 100 - elapsed: 77us
concatenation - 100 - elapsed: 1669us
creation - 100 - elapsed: 43us

builder - 1000 - elapsed: 511us
concatenation - 1000 - elapsed: 111504us
creation - 1000 - elapsed: 282us

builder - 10000 - elapsed: 3364us 
concatenation - 10000 - elapsed: 5709793us
creation - 10000 - elapsed: 972us

Wenn man die Ergebnisse für eine Verkettung nicht berücksichtigt (JIT hat seine Aufgabe noch nicht erfüllt), ist selbst für 10 Verkettungen die Leistungseinbuße relevant;Bei Tausenden von Verkettungen ist der Unterschied enorm.

Lehren aus diesem sehr schnellen Experiment (mit dem obigen Code leicht reproduzierbar):Verwenden Sie niemals das += um Strings miteinander zu verketten, selbst in sehr einfachen Fällen, in denen einige Verkettungen erforderlich sind (wie gesagt, das Erstellen neuer Strings ist ohnehin teuer und setzt den GC unter Druck).

Machen Sie die toString-Methode so lesbar wie möglich!

Die einzige Ausnahme hierfür ist in meinem Buch „Wenn Sie können“. beweisen Meiner Meinung nach verbraucht es erhebliche Ressourcen :) (Ja, das bedeutet Profiling)

Beachten Sie außerdem, dass der Java 5-Compiler schnelleren Code generiert als der handgeschriebene „StringBuffer“-Ansatz, der in früheren Java-Versionen verwendet wurde.Wenn Sie „+“ verwenden, sind diese und zukünftige Erweiterungen kostenlos.

Es scheint eine Debatte darüber zu geben, ob die Verwendung von StringBuilder bei aktuellen Compilern noch erforderlich ist.Also dachte ich, ich gebe meine 2 Cent Erfahrung ab.

Ich habe ein JDBC Ergebnissatz von 10.000 Datensätzen (ja, ich benötige sie alle in einem Stapel). Die Verwendung des +-Operators dauert auf meinem Computer mit etwa 5 Minuten Java 1.8.Benutzen stringBuilder.append("") Die gleiche Abfrage dauert weniger als eine Sekunde.

Der Unterschied ist also riesig.Innerhalb einer Schleife StringBuilder ist viel schneller.

Siehe das Beispiel unten:

//java8
static void main(String[] args) {
    case1();//str.concat
    case2();//+=
    case3();//StringBuilder
}

static void case1() {
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    String str = "";
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str = str.concat(UUID.randomUUID()+"---");
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:"+str.length()+" in "+(System.currentTimeMillis()-startTimeAll)+" ms");
}

static void case2() {
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    String str = "";
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str+=UUID.randomUUID()+"---";
        saveTime(savedTimes, startTime);
    }        
    System.out.println("Created string of length:"+str.length()+" in "+(System.currentTimeMillis()-startTimeAll)+" ms");
}

static void case3() {
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    StringBuilder str = new StringBuilder("");
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str.append(UUID.randomUUID()+"---");
        saveTime(savedTimes, startTime);
    }        
    System.out.println("Created string of length:"+str.length()+" in "+(System.currentTimeMillis()-startTimeAll)+" ms");

}

static void saveTime(List<Long> executionTimes, long startTime) {
        executionTimes.add(System.currentTimeMillis()-startTime);
        if(executionTimes.size()%CALC_AVG_EVERY == 0) {
            out.println("average time for "+executionTimes.size()+" concatenations: "+
                    NumberFormat.getInstance().format(executionTimes.stream().mapToLong(Long::longValue).average().orElseGet(()->0))+
                    " ms avg");
            executionTimes.clear();
        }
}

Ausgabe:

durchschnittliche Zeit für 10000 Verkettungen:0,096 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,185 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,327 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,501 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,656 ms durchschnittlich
Erstellte Zeichenfolge mit einer Länge von 1950000 Zoll 17745 ms
durchschnittliche Zeit für 10000 Verkettungen:0,21 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,652 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:1,129 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:1,727 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:2,302 ms durchschnittlich
Erstellte Zeichenfolge mit einer Länge von 1950000 Zoll 60279 ms
durchschnittliche Zeit für 10000 Verkettungen:0,002 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,002 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,002 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,002 ms durchschnittlich
durchschnittliche Zeit für 10000 Verkettungen:0,002 ms durchschnittlich
Erstellte Zeichenfolge mit einer Länge von 1950000 Zoll 100 ms

Mit zunehmender Stringlänge erhöht sich auch die Verkettungszeit.
Das ist, wo die StringBuilder ist auf jeden Fall nötig.
Wie Sie sehen, ist die Verkettung: UUID.randomUUID()+"---", hat keinen wirklichen Einfluss auf die Zeit.

P.S.: Ich glaube nicht Wann sollte StringBuilder in Java verwendet werden? ist wirklich ein Duplikat davon.
Diese Frage spricht über toString() was in den meisten Fällen keine Verkettungen großer Zeichenfolgen durchführt.

In Bezug auf die Leistung ist die String-Verkettung mit „+“ kostspieliger, da eine völlig neue Kopie des Strings erstellt werden muss, da Strings in Java unveränderlich sind.Dies spielt insbesondere dann eine Rolle, wenn die Verkettung sehr häufig ist, z. B.:innerhalb einer Schleife.Folgendes schlägt meine IDEE vor, wenn ich versuche, so etwas zu tun:

enter image description here

Allgemeine Regeln:

  • Innerhalb einer einzelnen String-Zuweisung ist die Verwendung der String-Verkettung in Ordnung.
  • Wenn Sie eine Schleife erstellen, um einen großen Block an Zeichendaten aufzubauen, wählen Sie StringBuffer.
  • Die Verwendung von += für einen String wird immer weniger effizient sein als die Verwendung eines StringBuffer, daher sollten hier Alarmglocken läuten – aber in bestimmten Fällen wird die gewonnene Optimierung im Vergleich zu den Lesbarkeitsproblemen vernachlässigbar sein, also nutzen Sie Ihren gesunden Menschenverstand.

Hier ist ein schöner Jon Skeet-Blog rund um dieses Thema.

Darf ich darauf hinweisen, dass Sie vielleicht einen Blick darauf werfen sollten, wenn Sie eine Sammlung durchlaufen und StringBuilder verwenden möchten Apache Commons Lang Und StringUtils.join() (in verschiedenen Geschmacksrichtungen)?

Unabhängig von der Leistung erspart es Ihnen die Erstellung von StringBuildern und for-Schleifen für scheinbar millionste Zeit.

Ich habe vier verschiedene Ansätze verglichen, um die Leistung zu vergleichen.Ich weiß nicht genau, was mit gc passiert, aber das Wichtigste für mich ist die Zeit.Der Compiler ist hier ein wichtiger Faktor. Ich habe jdk1.8.0_45 unter der Windows8.1-Plattform verwendet.

concatWithPlusOperator = 8
concatWithBuilder = 130
concatWithConcat = 127
concatStringFormat = 3737
concatWithBuilder2 = 46


public class StringConcatenationBenchmark {

private static final int MAX_LOOP_COUNT = 1000000;

public static void main(String[] args) {

    int loopCount = 0;
    long t1 = System.currentTimeMillis();
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithPlusOperator();
        loopCount++;
    }
    long t2 = System.currentTimeMillis();
    System.out.println("concatWithPlusOperator = " + (t2 - t1));

    long t3 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithBuilder();
        loopCount++;
    }
    long t4 = System.currentTimeMillis();
    System.out.println("concatWithBuilder = " + (t4 - t3));

    long t5 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithConcat();
        loopCount++;
    }
    long t6 = System.currentTimeMillis();
    System.out.println("concatWithConcat = " + (t6 - t5));

    long t7 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatStringFormat();
        loopCount++;
    }
    long t8 = System.currentTimeMillis();
    System.out.println("concatStringFormat = " + (t8 - t7));

    long t9 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithBuilder2();
        loopCount++;
    }
    long t10 = System.currentTimeMillis();
    System.out.println("concatWithBuilder2 = " + (t10 - t9));
}

private static void concatStringFormat() {
    String s = String.format("%s %s %s %s ", "String", "String", "String", "String");
}

private static void concatWithConcat() {
    String s = "String".concat("String").concat("String").concat("String");
}

private static void concatWithBuilder() {
    StringBuilder builder=new StringBuilder("String");
    builder.append("String").append("String").append("String");
    String s = builder.toString();
}

private static void concatWithBuilder2() {
    String s = new StringBuilder("String").append("String").append("String").append("String").toString();
}

private static void concatWithPlusOperator() {
    String s = "String" + "String" + "String" + "String";
}
}

Folgendes habe ich in Java8 überprüft

  • Verwendung der String-Verkettung
  • Verwendung von StringBuilder

    long time1 = System.currentTimeMillis();
    usingStringConcatenation(100000);
    System.out.println("usingStringConcatenation " + (System.currentTimeMillis() - time1) + " ms");
    
    time1 = System.currentTimeMillis();
    usingStringBuilder(100000);
    System.out.println("usingStringBuilder " + (System.currentTimeMillis() - time1) + " ms");
    
    
    private static void usingStringBuilder(int n)
    {
        StringBuilder str = new StringBuilder();
        for(int i=0;i<n;i++)
            str.append("myBigString");    
    }
    
    private static void usingStringConcatenation(int n)
    {
        String str = "";
        for(int i=0;i<n;i++)
            str+="myBigString";
    }
    

Es ist wirklich ein Albtraum, wenn Sie die String-Verkettung für eine große Anzahl von Strings verwenden.

usingStringConcatenation 29321 ms
usingStringBuilder 2 ms

Ich denke, wir sollten den StringBuilder-Append-Ansatz wählen.Grund ist

  1. Durch die String-Verkettung wird jedes Mal ein neues String-Objekt erstellt (da String ein unveränderliches Objekt ist), sodass 3 Objekte erstellt werden.

  2. Mit dem String Builder wird nur ein Objekt erstellt [StringBuilder ist veränderbar] und der weitere String wird daran angehängt.

Für einfache Zeichenfolgen wie diese bevorzuge ich die Verwendung

"string".concat("string").concat("string");

Der Reihe nach würde ich sagen, dass die bevorzugte Methode zum Erstellen einer Zeichenfolge die Verwendung von StringBuilder, String#concat() und dann dem überladenen +-Operator ist.StringBuilder führt zu einer deutlichen Leistungssteigerung bei der Verarbeitung großer Strings, genau wie die Verwendung des +-Operators zu einem starken Leistungsabfall führt (exponentiell starker Rückgang mit zunehmender String-Größe).Das einzige Problem bei der Verwendung von .concat() besteht darin, dass es NullPointerExceptions auslösen kann.

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