1121 Stimmen

StringBuilder gegen String-Konkatenation in toString() in Java

Angesichts der beiden unten stehenden toString()-Implementierungen, welche ist bevorzugt:

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 wir nur 3 Eigenschaften haben und es keinen Unterschied machen könnte, aber ab wann würden Sie von der Verwendung von + für die Konkatenierung zu StringBuilder wechseln?

63 Stimmen

An welchem Punkt wechseln Sie zu StringBuilder? Wenn es sich auf den Speicher oder die Leistung auswirkt. Oder wenn es sein könnte. Wenn Sie dies wirklich nur einmal für ein paar Zeichenfolgen tun, keine Sorgen. Aber wenn Sie es immer wieder tun werden, sollten Sie einen messbaren Unterschied feststellen, wenn Sie StringBuilder verwenden.

1 Stimmen

Was bedeutet 100 als Parameter?

3 Stimmen

@Unbekannt 100 ist die Anfangsgröße des StringBuilder

1130voto

Michael Borgwardt Punkte 334642

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

Viel wichtiger ist, dass wir nur 3 Eigenschaften haben, daher könnte es keinen Unterschied machen, aber ab wann wechseln Sie vom Konkatenieren zum Builder?

An dem Punkt, an dem Sie in einer Schleife konkatenieren - das ist normalerweise, wenn der Compiler StringBuilder nicht von alleine ersetzen kann.

0 Stimmen

Der Unterschied zwischen den beiden meistgenutzten Dekompilelr besteht bei der String-Verkettung: JAD zeigt StringBuilder, JD-GUI zeigt Verkettung an. Wenn Sie die .class-Datei in einem beliebigen Editor öffnen, sehen Sie StringBuilder-Verweise, daher wird die Optimierung durchgeführt, JD-GUI zeigt es nur auf eine "lesefreundlichere" Art - als Verkettung.

2 Stimmen

Ich glaube, eine weitere Überlegung bei der Optimierung der Verwendung von StringBuilder gegen das Verketten (außerhalb einer Schleife) ist, ob Sie mehrere Strings konstruieren. Ist der Compiler schlau genug, um den StringBuilder wiederzuverwenden, den er mit setLength(0) hinzufügt? Wenn nicht, können Sie dies manuell tun, anstatt den Compiler die Optimierung der Verkettung optimieren zu lassen, aber die Wiederverwendung des StringBuilders zu verpassen.

91 Stimmen

Nicht um ein bereits totgeschlagenes Pferd zu reiten, aber der Wortlaut in der Spezifikation lautet: Um die Leistung bei wiederholter Zeichenkettenverknüpfung zu steigern, kann ein Java-Compiler die StringBuffer-Klasse oder eine ähnliche Technik verwenden, um die Anzahl der Zwischen-String-Objekte zu reduzieren, die bei der Auswertung eines Ausdrucks erstellt werden. Das Schlüsselwort dort ist kann. Da dies offiziell optional ist (obwohl höchstwahrscheinlich implementiert), sollten wir uns nicht schützen?

307voto

joel.neely Punkte 30189

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

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

Aber wenn Sie einen String z.B. innerhalb einer Schleife aufbauen, verwenden Sie StringBuilder.

Zur Klarstellung, vorausgesetzt, hugeArray enthält Tausende von Strings, ist Code wie dieser:

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

sehr zeitaufwändig und speicherintensiv im Vergleich zu:

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

7 Stimmen

Ja, StringBuilder muss das String-Objekt nicht immer wieder neu erstellen.

183 Stimmen

Verdammt, ich habe diese 2 Funktionen verwendet, um einen großen String zu testen, an dem ich arbeite. 6,51 Minuten gegen 11 Sekunden

1 Stimmen

Übrigens können Sie auch result += s; nutzen (im ersten Beispiel)

91voto

Omry Yadan Punkte 27963

In den meisten Fällen werden Sie keinen tatsächlichen Unterschied zwischen den beiden Ansätzen sehen, aber es ist leicht, 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 ist, dass += zum Anhängen an einen String einen neuen String rekonstruiert, so dass es etwas kostet, das linear zur Länge Ihrer Strings (Summe beider) ist.

Also - zu Ihrer Frage:

Der zweite Ansatz wäre schneller, aber er ist weniger lesbar und schwerer zu warten. Wie gesagt, in Ihrem speziellen Fall würden Sie wahrscheinlich keinen Unterschied sehen.

0 Stimmen

Vergessen Sie nicht das .concat() zu verwenden. Ich würde vermuten, dass die verstrichene Zeit irgendwo zwischen 10 und 18 ms liegt, was vernachlässigbar ist, wenn Sie kurze Zeichenketten wie im ursprünglichen Beitrag verwenden.

11 Stimmen

Während du mit += richtig liegst, handelte es sich im Originalbeispiel um eine Folge von +, die der Compiler in einen einzelnen string.concat-Aufruf umwandelt. Deine Ergebnisse finden keine Anwendung.

1 Stimmen

@Blindy & Droo :- Ihr habt beide recht. Bei einem solchen Szenario ist die Verwendung von .concat die beste Lösung, da += jedes Mal ein neues Objekt erstellt, wenn die Schleife ausgeführt wird.

76voto

tangens Punkte 37853

Ich bevorzuge:

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

...weil es kurz und lesbar ist.

Ich würde dies nicht für Geschwindigkeit optimieren, es sei denn, Sie verwenden es in einer Schleife mit einer sehr hohen Wiederholungszahl und haben den Leistungsunterschied gemessen.

Ich stimme zu, dass diese Form bei der Ausgabe vieler Parameter verwirrend sein kann (wie einer der Kommentare sagt). In diesem Fall würde ich zu einer lesbareren Form wechseln (vielleicht unter Verwendung von ToStringBuilder von Apache Commons - entnommen aus der Antwort von matt b) und die Leistung erneut ignorieren.

71 Stimmen

Es ist tatsächlich länger, enthält mehr Symbole und hat Variablen aus einer Textfolge.

4 Stimmen

Würdest du sagen, dass es weniger lesbar ist als einer der anderen Ansätze?

3 Stimmen

Ich bevorzuge es, dies zu schreiben, weil es einfacher ist, weitere Variablen hinzuzufügen, aber ich bin mir nicht sicher, ob es lesbarer ist - besonders wenn die Anzahl der Argumente groß wird. Es funktioniert auch nicht, wenn Sie Teile zu verschiedenen Zeiten hinzufügen müssen.

34voto

Zofren Punkte 1130

Seit Java 1.5 generieren einfache einzeilige Verkettungen mit "+" und StringBuilder.append() genau den gleichen Bytecode.

Also verwenden Sie zur besseren Lesbarkeit des Codes "+".

2 Ausnahmen :

  • mehrfädige Umgebung : StringBuffer
  • Verkettung in Schleifen : StringBuilder/StringBuffer

4 Stimmen

Und vor Java 1.5 erzeugte einfache, einzeilige Konkatenation mit "+" und StringBuffer.append() genau denselben Bytecode (da StringBuilder nicht existierte). Seit Java 9 erzeugt einfache, einzeilige Konkatenation mit "+" potenziell besseren Code als StringBuilder.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X