2011-08-23 19 views
11

अक्सर यह तर्क दिया जाता है कि वस्तुओं (विशेष रूप से लूप में) से परहेज करना अच्छा अभ्यास माना जाता है।स्ट्रिंगबफर नया() या हटाएं (0, एसबी। लम्बाई()) अधिक कुशल क्या है?

फिर, 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 की तुलना में खराब प्रदर्शन करेगा। स्ट्रिंगबिल्डर थ्रेड सुरक्षित नहीं है लेकिन परिणामस्वरूप तेज़ है। अंत में, मैं setLength का उपयोग करके लंबाई को 0 पर सेट करना पसंद करता हूं।

sb.setLength(0) 

इस छोड़कर तुम सच में लंबाई के बारे में परवाह नहीं है .delete(...) के समान है। इसके अलावा शायद थोड़ा तेज़ है क्योंकि इसे 'कुछ भी हटाने की आवश्यकता नहीं है। नया StringBuilder (या स्ट्रिंगबफर) बनाना कम कुशल होगा। जब भी आप new देखते हैं तो जावा एक नई वस्तु बना रहा है और ढेर पर रख रहा है।

नोट: .delete और .setLength, .delete सेट लंबाई = 0, और .setLength सेट के कार्यान्वयन को देखने के बाद '\0' के लिए हर बात तो तुम मिल सकता है .delete

+0

यदि 'स्ट्रिंगबिल्डर' को बहुत बड़ा आंतरिक बफर आवंटित किया जाता है जो बर्बाद हो जाता है क्योंकि प्रारंभिक लूप पुनरावृत्ति एक बहुत बड़ी स्ट्रिंग का उत्पादन करता है, और बाद में पुनरावृत्तियों को नहीं करता है, तो आप जरूरी से अधिक लंबे समय तक थ्रैशिंग कर सकते हैं, लेकिन अन्यथा बफर को नेट जीतना है क्योंकि बाद में पुनरावृत्तियों तारों को लगभग समान आकार के समान आकार का उत्पादन करते हैं, तो आप इससे परहेज कर रहे हैं कुछ बफर प्रतियां। –

+1

'हटाएं' ओ (एन) नहीं है जब हटाएं पूरी सामग्री को साफ़ करती है। –

+0

यह सच है, मैं अपना जवाब अपडेट कर रहा हूं। लेकिन केवल जब लेन == गिनती है जो सच है यदि आप सभी को हटा रहे हैं। –

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

@ माइक मुझे यकीन नहीं है कि आपका मतलब क्या है 'लेन' 0 होगा। यह 'अंत - स्टार्ट' से गणना की जाती है जो 'sb.length() - 0' होगी। 'गिनती-अंत' कहने का आपका मतलब 0 होगा जो सच है। लेकिन आम तौर पर आप केवल पैरा के एक सेट के लिए ओ (एन) की गणना नहीं करते हैं। –

+0

@ एमीर, मुझे खेद है कि मुझे लगता है कि मैं कोई महत्वपूर्ण काम नहीं कर रहा था, लेकिन मैं क्यों गलत था। जब 'स्टार्ट' 0 होता है और' एंड '' गिनती 'उर्फ' यह। लम्बाई() 'है, तो आप 'System.arraycopy (मान, गिनती, मान, 0, 0)' कर रहे हैं। अंतिम 0 का मतलब है कि यह इंडेक्स गिनती से 0 बाइट्स को इंडेक्स 0 से कॉपी कर रहा है। –

3

बस पिछली टिप्पणी बढ़ाना:

स्रोत को देख से, delete() हमेशा System.arraycopy() कहता है, लेकिन तर्क हैं अगर (0, गिनती), यह की लंबाई के साथ arraycopy() कॉल करेंगे शून्य, जो संभवतः कोई प्रभाव नहीं होगा। आईएमएचओ, यह अनुकूलित किया जाना चाहिए क्योंकि मैं शर्त लगाता हूं कि यह सबसे आम मामला है, लेकिन कोई फर्क नहीं पड़ता।

setLength() के साथ, दूसरे हाथ पर, कॉल ensureCapacityInternal() (एक और बहुत ही सामान्य मामला है कि बाहर IMHO अनुकूलित किया जाना चाहिए था) और फिर करने के लिए एक कॉल के माध्यम से यदि आवश्यक हो तो StringBuilder की क्षमता में वृद्धि होगी delete के रूप में लंबाई ट्रंकेटस() किया होता।

आखिरकार, दोनों विधियां केवल count को शून्य पर सेट अप करें।

न तो कॉल इस मामले में कोई भी पुनरावृत्ति करता है। दोनों एक अनावश्यक समारोह कॉल करते हैं। हालांकि सुनिश्चित करें कि क्षमता इंटरनेशनल() एक बहुत ही सरल निजी विधि है, जो कंपाइलर को लगभग अस्तित्व से अनुकूलित करने के लिए आमंत्रित करती है, इसलिए यह संभावना है कि setLength() थोड़ा अधिक कुशल है।

मैं बहुत संदेह है कि StringBuilder का एक नया उदाहरण बनाने कभी बस शून्य करने के लिए count सेटिंग के रूप में के रूप में कुशल हो सकता है, लेकिन मुझे लगता है कि संकलक पैटर्न शामिल समझते हैं और करने के लिए बार-बार कॉल में दोहराया instantiations कन्वर्ट कर सकती है setLength (0)। लेकिन सबसे अच्छा, यह एक धो होगा। और आप मामले को पहचानने के लिए संकलक के आधार पर हैं।

कार्यकारी सारांश: सेटलेथेंथ (0) सबसे कुशल है। अधिकतम दक्षता के लिए, जब आप इसे बनाते हैं तो स्ट्रिंगबिल्डर में बफर स्पेस को पूर्व-आवंटित करें।