StringBuilder vs StringBuffer: क्या चुनें और क्यों यह महत्वपूर्ण है?
\n\nअगर आपने कभी Java में ऐसा कोड लिखा है जो स्ट्रिंग्स के साथ बहुत काम करता है (जैसे SQL क्वेरी बनाना, JSON फॉर्मेट करना, या दर्जनों टेक्स्ट के टुकड़ों को जोड़ना), तो आपने शायद इस दुविधा का सामना किया होगा: StringBuilder या StringBuffer? Stack Overflow पर इस सवाल को लाखों बार देखा गया है, और यह कोई संयोग नहीं है। पहली नज़र में ये दोनों क्लासेज़ एक जैसी लगती हैं - दोनों AbstractStringBuilder को एक्सटेंड करती हैं, दोनों mutable character array का उपयोग करती हैं, और दोनों में append(), insert(), delete() जैसे मेथड होते हैं। लेकिन असली फर्क बारीकियों में छिपा है।
इस आर्टिकल में हम सिर्फ अंतरों की लिस्ट नहीं देंगे। हम रियल-लाइफ उदाहरणों के साथ इन्हें समझेंगे, JVM के अंदर झांकेंगे, और उन सवालों के जवाब देंगे जो इंटरव्यू में जरूर पूछे जाते हैं। चलिए शुरू करते हैं!
\n\n1. सबसे बड़ा अंतर: सिंक्रोनाइज़ेशन
\n\nयह सबसे महत्वपूर्ण पॉइंट है, जिसके लिए यह पूरी बहस है। StringBuffer थ्रेड-सेफ (thread-safe) है। इसके लगभग सभी पब्लिक मेथड synchronized कीवर्ड से सिंक्रोनाइज़्ड होते हैं। StringBuilder सिंक्रोनाइज़्ड नहीं है। बस इतना ही फर्क है।
आइए कोड देखें (रियल JDK से सरलीकृत वर्जन):
\n\n// StringBuffer (Java 17)\npublic synchronized StringBuffer append(String str) {\n toStringCache = null;\n super.append(str);\n return this;\n}\n\n// StringBuilder\npublic StringBuilder append(String str) {\n super.append(str);\n return this;\n}\n\n\nबस एक लाइन synchronized - और पूरा फर्क। लेकिन यह एक लाइन सब कुछ बदल देती है: परफॉरमेंस, उपयोग का क्षेत्र, और एप्लिकेशन का आर्किटेक्चर।
StringBuffer कब उपयोग करें?
\n- \n
- जब आप मल्टीथ्रेडेड एप्लिकेशन लिख रहे हों। \n
- जब एक ही
StringBufferइंस्टेंस को कई थ्रेड्स बिना बाहरी सिंक्रोनाइज़ेशन के उपयोग कर रहे हों। \n - उदाहरण: एक लॉगर जो अलग-अलग थ्रेड्स से मैसेज इकट्ठा करके एक बफर में डालता है। \n
StringBuilder कब उपयोग करें?
\n- \n
- सिंगल-थ्रेडेड कोड (90% मामलों में)। \n
- मेथड के अंदर लोकल वेरिएबल्स।
- स्ट्रिंग कॉन्केटनेशन वाले लूप्स (कंपाइलर खुद StringBuilder सुझाता है)।
2. परफॉरमेंस: कौन तेज़ है?
\n\nयहाँ सब कुछ अनुमानित है: StringBuilder, StringBuffer से तेज़ है। कितना तेज़? लोड पर निर्भर करता है, लेकिन औसतन 2-5 गुना। आइए एक सरल बेंचमार्क से जाँच करें।
\n\npublic class PerformanceTest {\n private static final int ITERATIONS = 10_000_000;\n\n public static void main(String[] args) {\n // StringBuilder\n long start = System.nanoTime();\n StringBuilder sb = new StringBuilder();\n for (int i = 0; i < ITERATIONS; i++) {\n sb.append("a");\n }\n long sbTime = System.nanoTime() - start;\n\n // StringBuffer\n start = System.nanoTime();\n StringBuffer sbf = new StringBuffer();\n for (int i = 0; i < ITERATIONS; i++) {\n sbf.append("a");\n }\n long sbfTime = System.nanoTime() - start;\n\n System.out.println("StringBuilder: " + sbTime / 1_000_000 + " ms");\n System.out.println("StringBuffer: " + sbfTime / 1_000_000 + " ms");\n System.out.println("Buffer धीमा है " + (sbfTime / (double) sbTime) + " गुना");\n }\n}\n\n\nमेरे लैपटॉप (Intel i7, 16GB RAM, Java 17) पर परिणाम स्थिर है: StringBuilder ~180 ms, StringBuffer ~620 ms। लगभग 3.5 गुना का अंतर। और अगर इसमें रियल वर्क (पार्सिंग, फॉर्मेटिंग) जोड़ दें, तो यह अंतर और बढ़ सकता है। क्यों? क्योंकि हर synchronized कॉल में मॉनिटर चेक, लॉक एक्वायर करना और उसे रिलीज़ करना शामिल है। सिंगल-थ्रेडेड कोड में यह पूरी तरह से समय की बर्बादी है।