2011-08-23 7 views
11

オブジェクトの作成を避けること(特にループ内での)を避けることは良い方法と考えられることがよくあります。より効率的なStringBuffer new()またはdelete(0、sb.length())は何ですか?

次に、StringBufferに関して最も効率的なものは何ですか?

StringBuffer sb = new StringBuffer(); 
ObjectInputStream ois = ...; 

for (int i=0;i<1000;i++) { 

    for (j=0;i<10;j++) { 
     sb.append(ois.readUTF()); 
    } 
    ... 

    // Which option is the most efficient? 
    sb = new StringBuffer(); // new StringBuffer instance? 
    sb.delete(0,sb.length()); // or deleting content? 

} 

つまり、オブジェクトを作成する方が高速で、次に配列をループするということです。

+1

プロファイラーでテストしましたか?結果は何でしたか? –

+0

http://codereview.stackexchange.com/questions/7575/reusing-stringbuilder-or-creating-a-new-one – Flow

答えて

15

最初のStringBufferは、スレッドセーフであり、これは、StringBuilderと比べてパフォーマンスが悪くなります。 StringBuilderはスレッドセーフではありませんが、結果として高速です。最後に、setLengthを使用して長さを0に設定するほうが好きです。

sb.setLength(0) 

これは、実際に長さを気にしない限り、.delete(...)に似ています。 ''を削除する必要はないので、おそらくもう少し速いでしょう。新しいStringBuilder(またはStringBuffer)を作成することは効率が悪くなります。 new Javaは新しいオブジェクトを作成し、それをヒープに配置しています。

:だからあなたは.delete

+0

'StringBuilder'が非常に大きな内部バッファを取得し、初期ループが無駄になってしまった場合反復処理では非常に大きな文字列が生成され、その後の反復では必要ない場合は、必要以上に時間がかかりすぎる可能性がありますが、そうでなければバッファを保持するのはネット勝利です。それ以降の反復では以前の反復とほぼ同じサイズの文字列が生成されるため、いくつかのバッファコピー。 –

+1

削除がコンテンツ全体をクリアするとき、 'delete'はO(N)ではありません。 –

+0

これは本当です、私は私の答えを更新しています。しかし、len == countの場合のみ、すべてを削除する場合はtrueです。 –

1

で少し勝利を得ることができ.delete.setLengthの実装を見た後、.deleteセット長= 0、および.setLengthセットあらゆる事'\0'にdeleteメソッドは、これを実現していますway:

ご覧のとおり、配列を反復処理しません。ただ、以前のコメントを増幅する

+2

'System.arraycopy'とは何と思いますか? –

+0

@Mike 'len'は0であるとは分かりません。これは' end-start'から計算され、 'sb.length() - 0'になります。 'count-end'と言うのは、真である0になります。しかし、一般的には、1セットのパラメータに対してのみO(n)を計算しません。 –

+0

@Amir、申し訳ありません私は重要な仕事が行われていないことは間違いないと思いますが、なぜ私は間違っていました。 'start'が0で' end'が 'count'で' this.length() 'なら、' System.arraycopy(value、count、value、0、0) 'を実行します。最後の0は、インデックスカウントからインデックス0まで0バイトをコピーしていることを意味します。 –

3

:ソース、delete(見てから

)は常に)(System.arraycopyを呼び出しますが、引数は(0、カウント)であれば、それはの長さ)(arraycopyを呼び出しますおそらく効果がないでしょう。 IMHO、これは私がそれが最も一般的なケースだと思うので最適化されるべきですが、問題はありません。 setLength

()は、必要に応じて他の一方で、コールはensureCapacityInternal()の呼び出し(私見アウトに最適化されている必要があります別の非常に一般的なケース)を経由してのStringBuilderの容量を増加し、その後、deleteとして長さを切り捨て() 行っているだろう。

結局のところ、両方の方法では、countを0に設定するだけです。

この場合、どちらの呼び出しも反復処理を行いません。どちらも不必要な関数呼び出しを行います。しかし、EnsureCapacityInternal()は非常に単純なプライベートメソッドであり、コンパイラをほぼ完全に無効にするように促しているので、setLength()はやや効率的です。

私はStringBuilderの新しいインスタンスを作成することは、これまで単にゼロにcountを設定するほど効率的かもしれないことは非常に懐疑的だけど、私は、コンパイラ関与パターンを認識し、を繰り返し呼び出しに繰り返しインスタンスを変換するかもしれないと仮定setLength(0)。しかし、最善の場合、それは洗濯になります。そして、あなたはコンパイラがそのケースを認識することに依存しています。

エグゼクティブサマリー:setLength(0)が最も効率的です。効率を最大限に高めるには、作成時にStringBuilder内のバッファ領域を事前に割り当てます。

関連する問題