2017-04-24 12 views
7

के आकार की जांच करने का सबसे तेज़ तरीका मेरे पास लूप स्टेटमेंट के अंदर निम्न कोड है।
लूप में, तारों को एसबी (स्ट्रिंगबिल्डर) में जोड़ा जाता है और जांच की जाती है कि एसबी का आकार 5 एमबी तक पहुंच गया है या नहीं।जावा - स्ट्रिंग

if (sb.toString().getBytes("UTF-8").length >= 5242880) { 
    // Do something 
} 

यह ठीक काम करता है, लेकिन यह बहुत धीमी है
क्या यह करने के लिए सबसे तेज़ तरीका होगा (आकार की जाँच के संदर्भ में)?

उत्तर

8

आप UTF-8 लंबाई जल्दी का उपयोग कर

public static int utf8Length(CharSequence cs) { 
    return cs.codePoints() 
     .map(cp -> cp<=0x7ff? cp<=0x7f? 1: 2: cp<=0xffff? 3: 4) 
     .sum(); 
} 

गणना कर सकते हैं ASCII वर्ण सामग्री पर हावी है, यह थोड़ा तेज उपयोग करने के लिए हो सकता है

public static int utf8Length(CharSequence cs) { 
    return cs.length() 
     + cs.codePoints().filter(cp -> cp>0x7f).map(cp -> cp<=0x7ff? 1: 2).sum(); 
} 

इसके बजाए।

लेकिन आप भी पूरे आकार recalculating नहीं के अनुकूलन क्षमता है, लेकिन केवल नए टुकड़ा आप StringBuilder को जोड़ रहे हैं के आकार, कुछ एक जैसे विचार कर सकते हैं

StringBuilder sb = new StringBuilder(); 
    int length = 0; 
    for(…; …; …) { 
     String s = … //calculateNextString(); 
     sb.append(s); 
     length += utf8Length(s); 
     if(length >= 5242880) { 
      // Do something 

      // in case you're flushing the data: 
      sb.setLength(0); 
      length = 0; 
     } 
    } 

मतलब यह है कि अगर आप ' सरोगेट जोड़े वाले टुकड़ों को फिर से जोड़ना, वे हमेशा पूर्ण होते हैं और अपने हिस्सों में विभाजित नहीं होते हैं। सामान्य अनुप्रयोगों के लिए, यह हमेशा मामला होना चाहिए।

एक अतिरिक्त संभावना, Didier-L ने सुझाव दिया, गणना स्थगित करने के लिए जब तक अपने StringBuilder, के रूप में उससे पहले, यह एक UTF-8 एक सीमा से अधिक लंबाई असंभव है दहलीज भाग तीन की लंबाई तक पहुँच जाता है। हालांकि, यह केवल फायदेमंद होगा यदि ऐसा होता है कि आप कुछ निष्पादन में threshold/3 तक नहीं पहुंचते हैं।

+4

एक और अनुकूलन के रूप में, यह देखते हुए कि एक चरित्र में अधिकतम 3 बाइट्स लगते हैं, आप तब तक लंबाई की गणना करने से बच सकते हैं जब तक कि 'स्ट्रिंगबिल्डर' की लंबाई 5 एमबी/3 तक पहुंच जाती है। –

+0

@ होल्गर जेडीके -9 में 'स्ट्रिंग :: कोडपॉइंट्स' होंगे जो एएससीआईआईआई और गैर-एएससीआईआई स्ट्रिंग्स के बीच अंतर बनाएंगे ... यह तकनीक केवल यूटीएफ -8 के लिए काम करती है, यह अभी भी अच्छी है। – Eugene

+1

@ यूजीन: 'यूटीएफ -8' लंबाई की गणना इस अभ्यास का एकमात्र उद्देश्य है। इसके अलावा, जावा 9 के 'कोडपॉइंट्स()' के कार्यान्वयन से इस जवाब में कोई फर्क नहीं पड़ता। इस उत्तर के दो समाधानों के बीच अंतर यह है कि दूसरा एएससीआईआई अक्षरों के लिए केवल एक सशर्त निष्पादित करता है और अतिरिक्त संचालन को छोड़ देता है। गलती को ठीक करने के बाद, दो प्रकार अब सबसे खराब मामले में भिन्न नहीं हैं, इसलिए दूसरा हमेशा जीतता है। एक सस्ता "isAllASCII" विधि सहायक होगी, लेकिन जहां तक ​​मुझे पता है, जावा 9 केवल आईएसओ-लैटिन -1 और आंतरिक रूप से अन्य तारों के बीच अंतर करने जा रहा है। – Holger

8

यदि आप 1000 बार लूप करते हैं, तो आप 1000 स्ट्रिंग उत्पन्न करेंगे, फिर लंबाई प्राप्त करने के लिए "यूटीएफ -8 बाइट" सरणी में परिवर्तित करें।

मैं पहली लंबाई को संग्रहीत करके रूपांतरण को कम कर दूंगा। फिर, प्रत्येक पाश पर, केवल अतिरिक्त मान की लंबाई प्राप्त करें, फिर यह केवल एक अतिरिक्त है।

int length = sb.toString().getBytes("UTF-8").length; 
for(String s : list){ 
    sb.append(s); 
    length += s.getBytes("UTF-8").length; 
    if(...){ 
    ... 
    } 
} 

यह इस्तेमाल किया स्मृति को कम करेगा और रूपांतरण की लागत

2

स्ट्रिंगबिल्डर के बजाय बाइटएरे ऑटपुटस्ट्रीम और आउटपुटस्ट्रीमवाइटर का उपयोग करने पर विचार करें। आकार का परीक्षण करने के लिए ByteArrayOutputStream.size() का उपयोग करें।

संबंधित मुद्दे