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

3voto

wayne Punkte 405

Es ist erwähnenswert, dass wie von @ZhekaKozlov darauf hingewiesen wurde,

+ seit Java 9 schneller ist, es sei denn, der JVM weiß nicht, wie er es optimieren soll (z.B. Konkatenation in einer Schleife).

Ich habe den Bytecode für den folgenden Code überprüft (in Java 17):

public class StringBM {
    public String toStringPlus(String a) {
        return "{a:" + a + ", b:" + ", c: " + "}";
    }

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

Für toStringPlus:

 0: aload_1
 1: invokedynamic #7,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
 6: areturn

für toStringBuilder:

 0: new           #11                 // class java/lang/StringBuilder
 3: dup
 4: bipush        100
 6: invokespecial #13                 // Method java/lang/StringBuilder."":(I)V
 9: astore_2
10: aload_2
11: ldc           #16                 // String {a:
13: invokevirtual #18                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: aload_1
17: invokevirtual #18                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: ldc           #22                 // String , b:
22: invokevirtual #18                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: ldc           #24                 // String , c:
27: invokevirtual #18                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: ldc           #26                 // String }
32: invokevirtual #18                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35: invokevirtual #28                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
38: areturn

Die + Version ruft einfach die dynamische Funktion makeConcatWithConstants auf und übergibt das Methodenargument {a:\u0001, b:, c: } (\u0001 ist der Parameterplatzhalter).
Während die StringBuilder Version es auf die 'ehrliche' Weise machen muss.
Ich denke, wir können jetzt sehen, warum + schneller ist.

1voto

Brian Agnew Punkte 260470

Kann ich darauf hinweisen, dass Sie, wenn Sie über eine Sammlung iterieren und StringBuilder verwenden, vielleicht Apache Commons Lang und StringUtils.join() (in verschiedenen Varianten) überprüfen möchten?

Unabhängig von der Leistung wird es Ihnen ersparen, StringBuilders und For-Schleifen zu erstellen, so wie es zum millionsten Mal scheint.

1voto

Sudip Bhandari Punkte 1877

Leistungsmäßig ist die Zeichenkettenverkettung mit '+' teurer, da eine vollständige Kopie der Zeichenkette erstellt werden muss, da Zeichenketten in Java unveränderlich sind. Dies spielt eine besondere Rolle, wenn die Verkettung sehr häufig vorkommt, z.B. innerhalb einer Schleife. Folgendes schlägt mein IDE vor, wenn ich so etwas versuche:

Bildbeschreibung hier eingeben

Allgemeine Regeln:

  • Innerhalb einer einzelnen Zeichenkettenzuweisung ist die Verwendung der Zeichenkettenverkettung in Ordnung.
  • Wenn Sie eine große Menge an Zeichendaten durch Schleifen aufbauen möchten, verwenden Sie StringBuffer.
  • Die Verwendung von += bei einer Zeichenkette ist immer weniger effizient als die Verwendung eines StringBuffer, daher sollten Warnsignale ertönen - aber in bestimmten Fällen wird die erzielte Optimierung im Vergleich zu den Lesbarkeitsproblemen vernachlässigbar sein, also verwenden Sie Ihren gesunden Menschenverstand.

Hier ist ein schöner Blog von Jon Skeet zu diesem Thema.

3 Stimmen

Sie sollten StringBuffer niemals verwenden, es sei denn, Sie benötigen unbedingt synchronized access von mehreren Threads aus. Verwenden Sie stattdessen StringBuilder, der nicht synchronisiert ist und somit weniger Overhead hat.

-4voto

Droo Punkte 3097

Für einfache Zeichenfolgen wie diese ziehe ich es vor, zu verwenden

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

Der bevorzugte Weg zur Konstruktion einer Zeichenfolge besteht darin, StringBuilder, String#concat() und dann den überladenen + Operator zu verwenden. StringBuilder ist eine signifikante Leistungssteigerung bei der Arbeit mit großen Zeichenfolgen, ebenso wie die Verwendung des + Operators eine große Leistungsabnahme darstellt (exponentiell große Abnahme, wenn die Zeichenfolgengröße zunimmt). Ein Problem bei der Verwendung von .concat() ist, dass es NullPointerExceptions werfen kann.

11 Stimmen

Die Verwendung von concat() wird wahrscheinlich schlechter abschneiden als '+', da die JLS erlaubt, dass '+' in einen StringBuilder umgewandelt wird, und höchstwahrscheinlich führen dies alle JVMs durch oder verwenden eine effizientere Alternative - das Gleiche gilt wahrscheinlich nicht für concat, das in Ihrem Beispiel mindestens einen vollständigen Zwischenstring erstellen und verwerfen muss.

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