14

オブジェクトの作成(特にループ内)を回避することは良い習慣と見なされるとよく​​言われます。

それでは、何が最も効率的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?

}

つまり、オブジェクトの作成は配列をループするよりも高速であると主張することができます。

4

3 に答える 3

16

1StringBufferつ目は、スレッド セーフであり、 に比べてパフォーマンスが低下しStringBuilderます。StringBuilder はスレッド セーフではありませんが、結果として高速になります。最後に、setLengthを使用して長さを 0 に設定することをお勧めします。

sb.setLength(0)

これは に似て.delete(...)いますが、長さはあまり気にしません。また、何も「削除」する必要がないため、おそらく少し高速です。新しいStringBuilder(または StringBuffer) を作成すると、効率が低下します。newJava が新しいオブジェクトを作成し、それをヒープに配置していること がわかります。

.delete: andの実装を確認した後.setLength.delete長さ = 0 に.setLength設定し、すべてを に設定し'\0'ます。.delete

于 2011-08-23T23:57:26.763 に答える
3

以前のコメントを増幅するだけです:

ソースを見ると、delete() は常に () を呼び出しますSystem.arraycopyが、引数が (0,count)arraycopyの場合、長さゼロで () を呼び出すため、おそらく効果はありません。私見、これは最も一般的なケースだと思うので最適化する必要がありますが、問題ではありません。

一方、() を使用すると、必要に応じて()setLengthへの呼び出しを介して StringBuilder の容量が増加し(IMHO を最適化する必要がある別の非常に一般的なケース)、 () のように長さが切り捨てられます。ensureCapacityInternaldelete

count最終的には、どちらの方法も最終的にゼロに設定されてしまいます。

この場合、どちらの呼び出しも反復処理を行いません。どちらも不要な関数呼び出しを行います。ただし、ensureCapacityInternal() は非常に単純なプライベート メソッドであり、コンパイラがそれを最適化してほぼ存在しないようにするため、setLength() の方がわずかに効率的である可能性があります。

StringBuilder の新しいインスタンスを作成することが、単純にゼロに設定するのと同じくらい効率的である可能性があるかどうかは非常に懐疑的ですがcount、コンパイラーsetLength関連するパターンを認識し、繰り返されるインスタンス化を(0)への繰り返し呼び出しに変換する可能性があると思います。しかし、最良の場合、それは洗浄になります。そして、ケースを認識するためにコンパイラに依存しています。

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

于 2012-07-06T01:43:49.553 に答える
1

delete メソッドは次のように実装されます。

public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}

ご覧のとおり、配列を反復処理しません。

于 2011-08-24T00:04:48.370 に答える