ループ後の文字列バッファー/ビルダーのクリア


122

ループ後にJavaで文字列バッファをクリアして、次の反復で文字列バッファをクリアする方法を教えてください。


2
別の質問:ループを1回だけ繰り返すためにSBを使用するのはなぜですか?別の内部反復はありますか?A + B + C + Dを実行するだけの場合、SBは価値がありません(Javaコンパイラーは内部でSBを使用します)。文字列の一部を条件付きで追加する場合に役立ちますが、それ以外の場合は単に「+」を使用します。
helios

回答:


135

1つのオプションは、次のようにdeleteメソッドを使用することです。

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

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

別のオプション(ビットクリーナー)はsetLength(int len)を使用します。

sb.setLength(0);

詳細については、Javadocを参照してください。


15
少しゴミが少ないのは、ループ内でStringBufferを宣言するだけです。
Mark Elliot、

11
ああ、sb.setLength(0); ループ内で宣言するよりもクリーンで効率的です。あなたのソリューションは、StringBufferを使用することによるパフォーマンス上の利点に反します...
Jon

6
パフォーマンスの利点は、インスタンス化を保存することではなく、文字列の可変性に由来すると思います。1e8反復の簡単なテストを次に示します。ループ内(2.97秒):ideone.com/uyyTL14w、ループ外(2.87秒):ideone.com/F9lgsIxh
Mark Elliot

6
パフォーマンスといえば:マルチスレッドのシナリオでコードにアクセスしない限り、StringBufferではなくStringBuilderを使用する必要があります。javadocを参照してください。ほとんどの実装」。
RahelLüthy、2010

4
外部でSBを作成する唯一の利点は、SBの内部(潜在的に長い)char []が失われないことです。最初のイテレーターで十分に大きくなった場合、2番目のループでchar []のサイズを変更する必要はありません。しかし、利点を得るには、「明確な方法」は内部配列のサイズを維持する必要があります。setLengthはそれを行いますが、SBで使用されていないすべての文字を\ u0000に設定するため、初期容量が十分な新しいSBを作成するだけではパフォーマンスが低下します。ループ内で宣言する方が良いです。
helios

48

を再利用する最も簡単な方法StringBufferは、メソッドを使用することですsetLength()

public void setLength(int newLength)

あなたは次のようなケースがあるかもしれません

StringBuffer sb = new StringBuffer("HelloWorld");
// after many iterations and manipulations
sb.setLength(0);
// reuse sb

2
@MMahmoud、コード例ではのsetLength代わりに読む必要がありsetlengthます。
OnaBai

setLengthコードソースを確認すると、どのように機能していますか(gist.github.com/ebuildy/e91ac6af2ff8a6b1821d18abf2f8c9e1)ここでのカウントは常にnewLength(0)よりも大きくなりますか?
Thomas Decaux

20

次の2つのオプションがあります。

どちらかを使用:

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

または使用:

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

注意

ループ内でオブジェクトStringBufferStringBuilderオブジェクトを宣言しないでください。そうしないと、反復ごとに新しいオブジェクトが作成されます。オブジェクトの作成には、システムリソース、スペース、および時間がかかります。したがって、長期的には、可能であればループ内で宣言しないでください。



5

反復ごとに新しいStringBuffer(またはさらに良いStringBuilder)を作成することをお勧めします。パフォーマンスの違いはほんのわずかですが、コードは短くて単純になります。


2
そのようなパフォーマンスの違いの証拠がある場合は、それを共有してください。(Javaが最も多く使用されている場所の統計、および「ほぼ」の定義の下での統計も確認できて嬉しいです。)
Eli Acherkan

1
割り当て(Javaの新しいキーワード)は、同じオブジェクトの一部のフィールドを変更するよりもコストがかかることはよく知られています。「大部分」については、かなりJavaを使用している15億を超えるAndroidデバイスがあります。
Louis CAD

1
場合によっては、コードの読みやすさがパフォーマンスよりも重要であることに同意しますが、この場合、コードは1行にすぎません。また、ベンチマークを実行して、割り当てとオブジェクトの作成、さらにガベージコレクションをまったく行わない場合よりもコストがかかることを証明できます。私たちはループにいるので、それは関連する以上のものです。
Louis CAD

1
私もKnuthの見解に同意しましたが、彼の見解は必ずしも真実ではありません。CPUサイクルとメモリを潜在的に獲得するために1行だけ追加することは、絶対に悪いことではありません。あなたは考えをまっすぐにしすぎています。ループは通常何度も繰り返されることに注意してください。ループは何千回も繰り返される可能性があり、慎重に最適化しないと、モバイル(およびサーバーまたはコンピューター)で貴重なメガバイトを消費する可能性があります。
Louis CAD

1
私達は私達の両方の視点を十分に明確に述べたと思います、そして私はこれ以上の議論がこのコメントセクションに有益ではないと思います。私の答えが正しくない、誤解を招く、または不完全であると感じた場合は、あなたまたは誰でも-是非、編集したり、反対票を投じてください。
Eli Acherkan、2015年

5
public void clear(StringBuilder s) {
    s.setLength(0);
}

使用法:

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

読みやすくするために、これが最良の解決策だと思います。


2

すでに良い答えがあります。StringBufferとStringBuildのパフォーマンスの違いのベンチマーク結果を追加するだけで、ループで新しいインスタンスを使用するか、ループでsetLength(0)を使用します。

要約は次のとおりです。

  • StringBuilderはStringBufferよりもはるかに高速です
  • ループで新しいStringBuilderインスタンスを作成しても、setLength(0)と違いはありません。(setLength(0)には、新しいインスタンスを作成するよりも非常に小さな利点があります。)
  • ループで新しいインスタンスを作成するため、StringBufferはStringBuilderよりも遅い
  • StringBufferのsetLength(0)は、ループで新しいインスタンスを作成するよりも非常に遅くなります。

非常にシンプルなベンチマーク(手動でコードを変更し、別のテストを行います):

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));
}

}

ループ内の新しいStringBuilderインスタンス:時間コスト:3693、3862、3624、3742

StringBuilder setLength:時間コスト:3465、3421、3557、3408

ループ内の新しいStringBufferインスタンス:時間コスト:8327、8324、8284

StringBuffer setLength時間コスト:22878、23017、22894

再びStringBuilder setLengthを使用して、私のラボトップでStringBuffer setLengthにこのようなlongを使用する問題が発生しないようにしました:-)時間コスト:3448


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

このコードの方が速いと思います。


3
これにはパフォーマンスの問題があります。イテレーションごとに新しいオブジェクトを作成します
Aditya Singh

@AdityaSinghそれは完全に合理的なアプローチです。証拠のないパフォーマンスの問題を想定しないでください。
shmosel

何が起こっているかの理解に基づいて物事を仮定することは、知性の基礎です。
rghome 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.