Löschen eines String-Puffers / Builders nach der Schleife

122

Wie löscht man den String-Puffer in Java nach einer Schleife, damit die nächste Iteration einen Clear-String-Puffer verwendet?

Wasserfall
quelle
2
Eine andere Frage: Warum verwenden Sie einen SB nur für eine Iteration der Schleife? Gibt es eine andere innere Iteration? SB ist nicht wert, wenn Sie einfach A + B + C + D ausführen möchten (der Java-Compiler verwendet intern einen SB). Es ist hilfreich, wenn Sie Teile von Zeichenfolgen bedingt hinzufügen möchten, aber ansonsten ... verwenden Sie einfach "+".
Helios

Antworten:

135

Eine Möglichkeit besteht darin, die Löschmethode wie folgt zu verwenden:

StringBuffer sb = new StringBuffer();
for (int n = 0; n < 10; n++) {
   sb.append("a");

   // This will clear the buffer
   sb.delete(0, sb.length());
}

Eine andere Option (Bit Cleaner) verwendet setLength (int len) :

sb.setLength(0);

Siehe Javadoc für weitere Informationen:

Jon
quelle
15
Etwas weniger Müll wäre, einfach den StringBuffer innerhalb der Schleife zu deklarieren.
Mark Elliot
11
Ah, ich denke sb.setLength (0); ist sauberer und effizienter als das Deklarieren innerhalb der Schleife. Ihre Lösung widerspricht dem Leistungsvorteil der Verwendung von StringBuffer ...
Jon
6
Ich denke, der Leistungsvorteil liegt in der Veränderbarkeit der Zeichenfolgen und nicht in der Speicherung der Instanziierung. Hier ist ein kurzer Test von 1e8-Iterationen: Innenschleife (2.97s): ideone.com/uyyTL14w , Außenschleife (2.87s): ideone.com/F9lgsIxh
Mark Elliot
6
Apropos Leistung: Sofern in einem Multithread-Szenario nicht auf Ihren Code zugegriffen wird, sollten Sie StringBuilder anstelle von StringBuffer verwenden - siehe javadoc: "Wenn möglich, wird empfohlen, diese Klasse gegenüber StringBuffer vorzuziehen, da sie unter schneller ist die meisten Implementierungen ".
Rahel Lüthy
4
Der einzige Vorteil der Erstellung des SB außerhalb besteht darin, dass das interne (möglicherweise lange) Zeichen [] nicht verloren geht. Wenn es im ersten Iterator groß genug geworden ist, muss die zweite Schleife kein char [] ändern. Um den Vorteil zu erzielen, muss die "Clear-Methode" jedoch die Größe des internen Arrays beibehalten. setLength macht das, setzt aber auch alle nicht verwendeten Zeichen im SB auf \ u0000, so dass es weniger leistungsfähig ist, einfach einen neuen SB mit einer guten Anfangskapazität zu erstellen. Es ist besser, innerhalb der Schleife zu deklarieren.
Helios
48

Der einfachste Weg, das wiederzuverwenden, StringBufferist die Verwendung der MethodesetLength()

public void setLength(int newLength)

Sie können den Fall mögen

StringBuffer sb = new StringBuffer("HelloWorld");
// after many iterations and manipulations
sb.setLength(0);
// reuse sb
Mossaddeque Mahmood
quelle
2
@MMahmoud, Im Codebeispiel sollte es lesen setLengthstatt setlength.
OnaBai
Wenn ich die Codequelle setLength sehe, wie funktioniert sie ( gist.github.com/ebuildy/e91ac6af2ff8a6b1821d18abf2f8c9e1 )? Die Anzahl hier ist immer größer als newLength (0).
Thomas Decaux
20

Sie haben zwei Möglichkeiten:

Verwenden Sie entweder:

sb.setLength(0);  // It will just discard the previous data, which will be garbage collected later.  

Oder verwenden Sie:

sb.delete(0, sb.length());  // A bit slower as it is used to delete sub sequence.  

HINWEIS

Vermeiden Sie Deklarationen StringBufferoder StringBuilderObjekte innerhalb der Schleife, da sonst mit jeder Iteration neue Objekte erstellt werden. Das Erstellen von Objekten erfordert Systemressourcen, Speicherplatz und Zeit. Vermeiden Sie es daher auf lange Sicht, sie innerhalb einer Schleife zu deklarieren, wenn dies möglich ist.

Aditya Singh
quelle
5
buf.delete(0,  buf.length());
Suraj Chandran
quelle
5

Ich schlage vor, für jede Iteration eine neue StringBuffer(oder noch bessere StringBuilder) zu erstellen . Der Leistungsunterschied ist wirklich vernachlässigbar, aber Ihr Code wird kürzer und einfacher.

Eli Acherkan
quelle
2
Wenn Sie Hinweise auf einen solchen Leistungsunterschied haben, teilen Sie diese bitte mit. (Ich werde auch froh sein, Statistiken darüber zu sehen, wo Java am häufigsten verwendet wird und unter welcher Definition von "meistens".)
Eli Acherkan
1
Es ist bekannt, dass die Zuordnung (neues Schlüsselwort in Java) teurer ist als nur das Ändern einiger Felder desselben Objekts. Für "meistens", mit denen Sie hochgradig replavieren können, gibt es mehr als 1,5 Milliarden Android-Geräte, die alle Java verwenden.
Louis CAD
1
Ich bin damit einverstanden, dass in einigen Fällen die Lesbarkeit des Codes wichtiger ist als die Leistung, aber in diesem Fall ist es nur eine Codezeile! Und Sie können einen Benchmark durchführen, der Ihnen beweist, dass die Zuordnung und Objekterstellung sowie das Sammeln von Müll teurer ist, als dies überhaupt nicht zu tun. Da wir uns in einer Schleife befinden, ist dies mehr als relevant.
Louis CAD
1
Ich habe auch Knuths Ansicht unterschrieben, aber seine Sichtweise ist nicht immer wahr. Das Hinzufügen von nur einer Zeile, um potenziell CPU-Zyklen und Speicher zu gewinnen, ist absolut nicht böse. Sie nehmen die Idee zu klar. Beachten Sie, dass eine Schleife normalerweise viele Male wiederholt wird. Eine Schleife kann tausende Male wiederholt werden, was auf einem Mobiltelefon (und auch auf einem Server oder Computer) wertvolle Megabyte verbrauchen kann, wenn sie nicht sorgfältig optimiert wird.
Louis CAD
1
Ich denke, wir haben beide unsere Standpunkte klar genug dargelegt, und ich bin der Meinung, dass eine weitere Diskussion für diesen Kommentarbereich nicht von Vorteil sein wird. Wenn Sie der Meinung sind, dass meine Antwort falsch, irreführend oder unvollständig ist, können Sie - oder jeder andere - sie auf jeden Fall bearbeiten und / oder ablehnen.
Eli Acherkan
5
public void clear(StringBuilder s) {
    s.setLength(0);
}

Verwendung:

StringBuilder v = new StringBuilder();
clear(v);

Aus Gründen der Lesbarkeit halte ich dies für die beste Lösung.

Ido Kessler
quelle
2

Schon gute Antwort da. Fügen Sie einfach ein Benchmark-Ergebnis für den Leistungsunterschied zwischen StringBuffer und StringBuild hinzu. Verwenden Sie eine neue Instanz in der Schleife oder setLength (0) in der Schleife.

Die Zusammenfassung lautet: In einer großen Schleife

  • StringBuilder ist viel schneller als StringBuffer
  • Das Erstellen einer neuen StringBuilder-Instanz in einer Schleife hat keinen Unterschied zu setLength (0). (setLength (0) hat einen sehr sehr kleinen Vorteil als das Erstellen einer neuen Instanz.)
  • StringBuffer ist langsamer als StringBuilder, indem eine neue Instanz in einer Schleife erstellt wird
  • setLength (0) von StringBuffer ist extrem langsamer als das Erstellen einer neuen Instanz in einer Schleife.

Sehr einfacher Benchmark (ich habe den Code nur manuell geändert und verschiedene Tests durchgeführt):

public class StringBuilderSpeed {
public static final char ch[] = new char[]{'a','b','c','d','e','f','g','h','i'};

public static void main(String a[]){
    int loopTime = 99999999;
    long startTime = System.currentTimeMillis();
    StringBuilder sb = new StringBuilder();
    for(int i = 0 ; i < loopTime; i++){
        for(char c : ch){
            sb.append(c);
        }
        sb.setLength(0);
    }
    long endTime = System.currentTimeMillis();
    System.out.println("Time cost: " + (endTime - startTime));
}

}}

Neue StringBuilder-Instanz in Schleife: Zeitkosten: 3693, 3862, 3624, 3742

StringBuilder setLength: Zeitkosten: 3465, 3421, 3557, 3408

Neue StringBuffer-Instanz in Schleife: Zeitkosten: 8327, 8324, 8284

StringBuffer setLength Zeitkosten: 22878, 23017, 22894

Wieder StringBuilder setLength, um sicherzustellen, dass mein Labtop kein Problem damit hat, so lange für StringBuffer setLength zu verwenden :-) Zeitkosten: 3448

Hao
quelle
0
StringBuffer sb = new SringBuffer();
// do something wiht it
sb = new StringBuffer();

Ich denke, dieser Code ist schneller.

Binh Phung
quelle
3
Dies hat Leistungsprobleme. Es erstellt nach jeder Iteration ein neues Objekt
Aditya Singh
@AdityaSingh Es ist ein völlig vernünftiger Ansatz. Nehmen Sie keine Leistungsprobleme ohne Beweise an.
Shmosel
Die Annahme von Dingen, die auf einem Verständnis dessen beruhen, was vor sich geht, ist die Grundlage der Intelligenz.
rghome