Best Practices / Leistung: Mischen von StringBuilder.append mit String.concat

86

Ich versuche zu verstehen, was die beste Vorgehensweise ist und warum String-Literale und -Variablen für verschiedene Fälle verkettet werden. Zum Beispiel, wenn ich solchen Code habe

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

Ist das der Weg, es zu tun? In diesem Beitrag habe ich festgestellt, dass der +Operator für Strings eine neue Instanz von StringBuilder erstellt, die Operanden verkettet und eine String-Konvertierung zurückgibt. Dies scheint viel mehr Arbeit zu bedeuten als nur aufzurufen .append(). Wenn das stimmt, kommt das nicht in Frage. Aber was ist mit String.concat()? Ist es richtig, .append()für jede Verkettung zu verwenden? Oder nur für Variablen, und es ist in Ordnung, Literale anzuhängen .concat()?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

Was sind die allgemeinen Regeln für Best Practices und Leistung, um diese Situationen zu bewältigen? Ist meine Annahme richtig auf+ und sollte sie wirklich einfach nicht verwendet werden?

Nick Rolando
quelle
Ich denke im Grunde hast du es. Es gibt unterschiedliche Meinungen darüber, ob String + "wirklich einfach nicht verwendet werden sollte". Der Punkt ist, dass Sie die Konsequenzen verstehen
ControlAltDel

Antworten:

184

+ Operator

String s = s1 + s2

Hinter den Kulissen bedeutet dies:

String s = new StringBuilder(s1).append(s2).toString();

Stellen Sie sich vor, wie viel zusätzliche Arbeit Sie hinzufügen, wenn Sie s1 + s2hier haben:

stringBuilder.append(s1 + s2)

anstatt:

stringBuilder.append(s1).append(s2)

Mehrere Saiten mit +

Bemerkenswert:

String s = s1 + s2 + s3 + ... +sN

wird übersetzt in:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

StringErstellt ein char[]Array, das sowohl für s1als auch passt s2. Kopien s1und s2Inhalte in dieses neue Array. Tatsächlich erfordert weniger Arbeit als der +Bediener.

StringBuilder.append()

Verwaltet ein internes char[]Array, das bei Bedarf wächst. Es char[]wird kein Extra erstellt, wenn das interne ausreichend groß ist.

stringBuilder.append(s1.concat(s2))

Die Leistung ist ebenfalls schlecht, da s1.concat(s2)ein zusätzliches char[]Array und Kopien erstellt werden s1und s2nur, um den neuen Array-Inhalt in das interne zu kopierenStringBuilder char[] .

Davon abgesehen sollten Sie die append()ganze Zeit verwenden und rohe Zeichenfolgen anhängen (Ihr erstes Code-Snippet ist korrekt).

Tomasz Nurkiewicz
quelle
Vielen Dank für Ihre Hilfe und die ausführliche Erklärung. das habe ich wirklich gebraucht.
Nick Rolando
12
Obwohl neuere Versionen des Compilers den Operator + automatisch für einen String-Builder optimieren, ist es nicht unbedingt eine gute Annahme, dass dies der Fall ist, da ältere Versionen dies nicht tun. Es gibt ein sehr wichtiges Thema, das in dieser ganzen Diskussion ignoriert wird. Dies ist einer der Hauptzwecke für StringBuilder, nämlich der String-Pool. Die Verwendung eines String-Builders behält alles als char [] bei und erstellt keinen Zwischen-String wie der Operator + vor den Compiler-Optimierungen (nur zum Ausführen eines Concats). Mit concat wird ein Zwischenzeichenfolgenobjekt erstellt, das zwischengespeichert, aber nicht verwendet wird.
LINEMAN78
Wenn ich also eine einmalige Anweisung (nicht mehrere Anweisungen für eine Methode) durchführe, verkettet ich mehrere verschiedene Zeichenfolgen. Es wäre in Ordnung, +die String-Objekte zu verwenden, anstatt StringBuilderfür diese einmalige Verkettung eine zu erstellen , da dies im Grunde das Gleiche bewirkt.
Nick Rolando
1
Und wenn ich nur ein Zeichen zusammenfassen möchte, ist es besser, .append ('\ n') anstelle von .append ("\ n") zu verwenden? Ist ein Zeichen ein primitiver Typ und ein String ein Objekt?
vrwim
3
Effektive Java 2nd Edition : Die wiederholte Verwendung des String-Verkettungsoperators zum Verketten von n Strings erfordert eine quadratische Zeit in n. Ist es also immer noch relevant?
Gkiko
16

Der Compiler optimiert die + Verkettung.

So

int a = 1;
String s = "Hello " + a;

verwandelt sich in

new StringBuilder().append("Hello ").append(1).toString();

Hier gibt es ein ausgezeichnetes Thema , das erklärt, warum Sie den Operator + verwenden sollten.

Andy Turner
quelle
3
Der Compiler würde dies tatsächlich optimieren, String s = "Hello World";da Sie Literale verwenden.
ColinD
@ColinD: +1. Habe gerade mein Snippet modifiziert.
3

Die Optimierung erfolgt automatisch durch den Compiler.

Der Java2-Compiler konvertiert automatisch Folgendes:

String s = s1 + s2; 

zu

String s = (new StringBuffer()).append(s1).append(s2).toString();

Entnommen direkt aus der Java Best Practices on Oracles-Website.

BoldAsLove
quelle
2

Sie sollten immer verwenden append.

concat Erstelle einen neuen String, so dass es ziemlich ähnlich ist + ich denke.

Wenn Sie concatoder +mit 2 final String verwenden, kann die JVM eine Optimierung vornehmen, sodass dies in diesem Fall dasselbe ist wie beim Anhängen.

alain.janinm
quelle
1

Wenn Sie genau zwei Strings zusammenfassen, verwenden Sie String.concat (erstellt einen neuen String, indem Sie ein neues char-Array erstellen, das zu beiden Strings passt, und kopieren die char-Arrays beider Strings hinein).

Wenn Sie mehrere (mehr als zwei) Strings in einer Zeile zusammenfassen, verwenden Sie + oder StringBuilder.append. Dies spielt keine Rolle, da der Compiler + in StringBuilder.append konvertiert. Dies ist gut für mehrere Strings, da ein char-Array beibehalten wird, das nach Bedarf wächst.

Wenn Sie mehrere Strings über mehrere Zeilen zusammenfassen, erstellen Sie einen StringBuilder und verwenden Sie die Append-Methode. Wenn Sie mit dem Anhängen von Strings an den StringBuilder fertig sind, verwenden Sie die Methode .toString () -, um daraus einen String zu erstellen. Für das Konkatieren in mehreren Zeilen ist dies schneller als die zweite Methode, da die zweite Methode in jeder Zeile einen neuen StringBuilder erstellen, die Strings anhängen und dann wieder in String umwandeln würde, während die dritte Methode nur einen StringBuilder für das Ganze verwendet.

Dakkaron
quelle
0

Der +Bediener ist eine bewährte Methode, er ist auch einfach und lesbar.

Die Java-Sprache bietet spezielle Unterstützung für den String-Verkettungsoperator (+) und für die Konvertierung anderer Objekte in Strings. Die Verkettung von Zeichenfolgen wird über die Klasse StringBuilder (oder StringBuffer) und ihre Append-Methode implementiert.

Offizielles Dokument: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

Mach Nhu Vy
quelle
0

In der Byte-Code-Ebene gibt es keine Unterschiede, und wir beeinträchtigen dort nicht die Effizienz. Bei der Ausführung der Bytecode-Ebene muss die Nicht-Inline-Operator-Überladungsmethode für + durch Aufrufen von append durchlaufen werden. dann in Assemblersprachenebene (Java ist in C geschrieben und C erzeugt Assemblys ähnlich wie Assembly, es wird ein zusätzlicher Registeraufruf zum Speichern des + Methodenaufrufs im Stapel und ein zusätzlicher Push ausgeführt (in Wirklichkeit kann der Cross-Compiler den + Operator optimieren Rufen Sie an, in diesem Fall macht es keinen Unterschied mit der Effizienz.)

Es ist eine gute Praxis, einen Weg zu haben, um die Lesbarkeit zu verbessern. :) :)

Shevon Silva
quelle
0

Ich persönlich bevorzuge den Strings.format()einfachen, leicht lesbaren einzeiligen String-Formatierer .

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F
T04435
quelle
0

Alle Antworten sind ziemlich gut und erklärend. Ich war jedoch der Meinung, dass die Erforschung anderer Techniken zur Verkettung von Zeichenfolgen ebenfalls hilfreich sein würde, z. B. Guava Joiner, Streams, String.format usw.

Für vollständige Details über die Leistung jeder Verkettungstechnik Java-String-Verkettung-welcher-Weg-ist-am besten .

Kurz gesagt, die Verkettungsleistung variiert mit Nein. von zu verkettenden Zeichenfolgen. Zum Beispiel - um 1-10 Zeichenfolgen zu verketten, funktionieren diese Techniken am besten - StringBuilder, StringBuffer und Plus Operator. Und um Hunderte von Strings zu verketten - Guava Joiner - funktioniert auch die stringUtils-Bibliothek von Apache hervorragend.

Bitte gehen Sie durch den obigen Blog. Dies erklärt die Leistungseffizienz sehr gut.

Vielen Dank.

coderAJ
quelle