2011-08-23 86 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.setLength.delete集長度= 0,.setLength套實施後的每一件事,以'\0'所以,你可以得到一個小贏與.delete

+0

如果'StringBuilder'獲得一個非常大的內部緩衝區,因爲早期循環而被浪費迭代會產生一個非常大的字符串,並且以後的迭代不會,那麼最終可能會導致比所需時間更長的抖動,否則保持緩衝區是一個淨勝利,因爲如果後面的迭代產生的字符串幾乎與早期迭代的字符串大小相同,一些緩衝區副本。 –

+1

當刪除清除整個內容時,'delete'不是O(N)。 –

+0

這是真的,我正在更新我的答案。但只有當len ==計數,如果你正在刪除所有內容,這是真的。 –

1

刪除方法實施該方式:

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

正如你可以看到它不遍歷數組。

+2

你覺得'System.arraycopy'的確如何? –

+0

@Mike我不確定你的意思是什麼'len'將會是0.它是從'end - start'計算出來的,它將'sb.length() - 0'。你說'count-end'的意思是0,這是真的。但通常你不會爲一組參數計算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()的長度零,這可能會沒有效果。恕我直言,這應該被優化,因爲我敢打賭這是最常見的情況,但不管。

隨着setLength(),在另一方面,該呼叫通過呼叫如果需要將增加的StringBuilder的能力ensureCapacityInternal(),然後(應該已經優化了IMHO另一種非常常見的情況)截斷長度delete () 會做。

最終,這兩種方法只是拉閘設置count爲零。

無論呼叫確實在這種情況下,任何迭代。兩者都進行不必要的功能調用。然而ensureCapacityInternal()是一個非常簡單的私有方法,其中邀請編譯器優化它幾乎不存在了,因此很可能是setLength()會更有效。

我非常懷疑,創造的StringBuilder的一個新實例可能永遠不會簡單地設置count零,高效的,但我想,編譯器可能承認參與模式和重複實例轉換成重複調用setLength(0)。但最好的是,這將是一場洗禮。你要依靠編譯器來識別這個案例。

執行摘要:setLength(0)是最有效的。爲了獲得最大的效率,當您創建它時,請在StringBuilder中預先分配緩衝區空間。

相關問題