{{ ... }}
जावा में डबल ब्रेस इनिशियलाइज़ेशन सिंटैक्स ( ) क्या है ?
{{ ... }}
जावा में डबल ब्रेस इनिशियलाइज़ेशन सिंटैक्स ( ) क्या है ?
जवाबों:
डबल ब्रेस आरंभीकरण निर्दिष्ट वर्ग ( बाहरी ब्रेसिज़) से उत्पन्न एक अनाम वर्ग बनाता है , और उस वर्ग ( आंतरिक ब्रेसिज़) के भीतर एक इनिशियर ब्लॉक प्रदान करता है । जैसे
new ArrayList<Integer>() {{
add(1);
add(2);
}};
ध्यान दें कि इस डबल ब्रेस इनिशियलाइज़ेशन का उपयोग करने का एक प्रभाव यह है कि आप अनाम आंतरिक कक्षाएं बना रहे हैं। निर्मित वर्ग में this
आसपास के बाहरी वर्ग के लिए एक अंतर्निहित सूचक होता है। जबकि सामान्य रूप से कोई समस्या नहीं है, यह कुछ परिस्थितियों में दु: ख पैदा कर सकता है जैसे कि धारावाहिक या कचरा एकत्र करना, और यह इस बारे में जागरूक होने के लायक है।
हर बार जब कोई डबल ब्रेस इनिशियलाइज़ेशन का उपयोग करता है, तो एक बिल्ली का बच्चा मारा जाता है।
वाक्यविन्यास असामान्य होने के अलावा और वास्तव में मुहावरेदार नहीं है (स्वाद बहस योग्य है, निश्चित रूप से), आप अनावश्यक रूप से अपने आवेदन में दो महत्वपूर्ण समस्याएं पैदा कर रहे हैं, जिनके बारे में मैंने हाल ही में यहां और अधिक विस्तार से ब्लॉग किया है ।
हर बार जब आप डबल ब्रेस इनिशियलाइज़ेशन का उपयोग करते हैं तो एक नया वर्ग बनाया जाता है। उदाहरण के लिए:
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
... इन कक्षाओं का उत्पादन करेंगे:
Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class
यह आपके क्लास लोडर के लिए बहुत अधिक उपरि है - बिना कुछ लिए! यदि आप इसे एक बार करते हैं, तो निश्चित रूप से यह अधिक आरंभिक समय नहीं लेगा। लेकिन अगर आप अपने उद्यम आवेदन में यह 20'000 गुना करते हैं ... तो बस "सिंटेक्स शुगर" के लिए यह सब स्मृति को ढेर कर देता है?
यदि आप उपरोक्त कोड लेते हैं और उस नक्शे को किसी विधि से वापस करते हैं, तो उस विधि के कॉलर बहुत ही भारी संसाधनों पर निर्बाध रूप से पकड़े जा सकते हैं जो कचरा एकत्र नहीं किया जा सकता है। निम्नलिखित उदाहरण पर विचार करें:
public class ReallyHeavyObject {
// Just to illustrate...
private int[] tonsOfValues;
private Resource[] tonsOfResources;
// This method almost does nothing
public Map quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
return source;
}
}
Map
अब दिए गए एन्क्लोज़िंग इंस्टेंस के संदर्भ में रिटर्न होगा ReallyHeavyObject
। आप शायद यह जोखिम नहीं लेना चाहते:
Http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-ant-pattern/ से छवि
आपके वास्तविक प्रश्न का उत्तर देने के लिए, लोग इस वाक्यविन्यास का उपयोग यह ढोंग करने के लिए कर रहे हैं कि जावा के पास कुछ शब्द हैं जैसे कि मौजूदा मोबाइल साहित्य के समान, नक्शा मानचित्र।
String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};
कुछ लोगों को यह वाक्यात्मक रूप से उत्तेजक लग सकता है।
{{...}}
और एक static
क्षेत्र के रूप में घोषित किया जाता है , तो किसी भी संभावित मेमोरी लीक, केवल एक अनाम वर्ग और कोई संलग्न उदाहरण संदर्भ नहीं होना चाहिए, है ना?
Map.of()
में उस उद्देश्य के लिए है, इसलिए यह एक बेहतर समाधान होगा
ReallyHeavyObject
। इसके अलावा, अनाम आंतरिक वर्ग, वर्ग निकाय के भीतर उपयोग किए जाने वाले सभी स्थानीय चरों पर कब्जा कर लेते हैं, इसलिए यदि आप इस पैटर्न के साथ संग्रह या मानचित्र को इनिशियलाइज़ करने के लिए न केवल स्थिरांक का उपयोग करते हैं, तो आंतरिक वर्ग के उदाहरण उन सभी को पकड़ लेंगे और वास्तव में हटाए जाने पर भी उनका संदर्भ लेते रहेंगे। संग्रह या मानचित्र। तो यह मामला है कि, इन उदाहरणों को संदर्भों के लिए आवश्यक स्मृति के रूप में केवल दो बार की आवश्यकता नहीं है, लेकिन उस संबंध में एक और स्मृति रिसाव है।
उदाहरण के लिए:
public class TestHashMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>(){
{
put("1", "ONE");
}{
put("2", "TWO");
}{
put("3", "THREE");
}
};
Set<String> keySet = map.keySet();
for (String string : keySet) {
System.out.println(string+" ->"+map.get(string));
}
}
}
यह काम किस प्रकार करता है
पहले ब्रेस एक नया बेनामी इनर क्लास बनाता है। ये आंतरिक कक्षाएं अपने मूल वर्ग के व्यवहार तक पहुंचने में सक्षम हैं। तो, हमारे मामले में, हम वास्तव में हैशसेट वर्ग का एक उपवर्ग बना रहे हैं, इसलिए यह आंतरिक वर्ग पुट () पद्धति का उपयोग करने में सक्षम है।
और ब्रेसिज़ का दूसरा सेट उदाहरण शुरुआती के अलावा कुछ भी नहीं है। यदि आप कोर जावा अवधारणाओं को याद दिलाते हैं, तो आप संरचना जैसे समान ब्रेस के कारण स्थैतिक इनिशियलाइज़र के साथ आसानी से इंस्टाइज़र ब्लॉक को जोड़ सकते हैं। केवल अंतर यह है कि स्थिर इनिशियलाइज़र को स्थैतिक कीवर्ड के साथ जोड़ा जाता है, और केवल एक बार चलाया जाता है; कोई फर्क नहीं पड़ता कि आप कितनी वस्तुओं का निर्माण करते हैं।
डबल ब्रेस इनिशियलाइज़ेशन के मज़ेदार एप्लिकेशन के लिए, जावा में डवेमी के एरे को देखें ।
अंश
private static class IndustrialRaverMonkey
extends Creature.Base {{
life = 46;
strength = 35;
charisma = 91;
weapon = 2;
}}
private static class DwarvenAngel
extends Creature.Base {{
life = 540;
strength = 6;
charisma = 144;
weapon = 50;
}}
और अब, BattleOfGrottoOfSausageSmells
और ... चंकी बेकन के लिए तैयार रहें !
मुझे लगता है कि यह तनावपूर्ण है कि जावा में "डबल ब्रेस इनिशियलाइज़ेशन" जैसी कोई चीज़ नहीं है । Oracle वेब-साइट में यह शब्द नहीं है। इस उदाहरण में दो विशेषताएं एक साथ उपयोग की जाती हैं: अनाम वर्ग और इनिशलाइज़र ब्लॉक। पुराने इनिशियलाइज़र ब्लॉक की तरह लगता है कि डेवलपर्स द्वारा भूल गए हैं और इस विषय में कुछ भ्रम पैदा करते हैं। Oracle डॉक्स से उद्धरण :
उदाहरण के लिए शुरुआती ब्लॉक वैरिएबल सिर्फ स्टैटिक इनिशियलाइज़र ब्लॉक की तरह दिखते हैं, लेकिन स्टैटिक कीवर्ड के बिना:
{
// whatever code is needed for initialization goes here
}
1- डबल ब्रेसेस जैसी कोई चीज नहीं है:
मैं यह बताना चाहता हूं कि डबल ब्रेस इनिशियलाइजेशन जैसी कोई चीज नहीं है। केवल सामान्य पारंपरिक एक ब्रेस इनिशियलाइज़ेशन ब्लॉक है। दूसरे ब्रेसिज़ ब्लॉक का आरंभीकरण से कोई लेना-देना नहीं है। उत्तर कहते हैं कि वे दो ब्रेसिज़ किसी चीज़ को शुरू करते हैं, लेकिन यह ऐसा नहीं है।
2- यह केवल अनाम कक्षाओं के बारे में नहीं है, बल्कि सभी वर्गों के बारे में है:
लगभग सभी उत्तर यह बताते हैं कि अनाम आंतरिक कक्षाओं को बनाते समय इसका उपयोग किया जाता है। मुझे लगता है कि उन उत्तरों को पढ़ने वाले लोगों को यह आभास होगा कि इसका उपयोग केवल अनाम आंतरिक कक्षाओं को बनाते समय किया जाता है। लेकिन इसका उपयोग सभी वर्गों में किया जाता है। उन जवाबों को पढ़कर ऐसा लगता है जैसे कुछ ब्रांड की नई खासियत है जो गुमनाम कक्षाओं के लिए समर्पित है और मुझे लगता है कि यह भ्रामक है।
3- उद्देश्य सिर्फ एक दूसरे के बाद कोष्ठक रखने के बारे में है, नई अवधारणा नहीं:
आगे जाकर, यह प्रश्न उस स्थिति के बारे में बात करता है जब दूसरा उद्घाटन ब्रैकेट पहले खोलने वाले ब्रैकेट के बाद होता है। जब सामान्य वर्ग में उपयोग किया जाता है तो आमतौर पर दो ब्रेसिज़ के बीच कुछ कोड होता है, लेकिन यह पूरी तरह से एक ही बात है। तो यह कोष्ठक रखने की बात है। इसलिए मुझे लगता है कि हमें यह नहीं कहना चाहिए कि यह कुछ नई रोमांचक चीज है, क्योंकि यह वह चीज है जिसे हम सभी जानते हैं, लेकिन सिर्फ कोष्ठक के बीच कुछ कोड के साथ लिखा जाता है। हमें "डबल ब्रेस इनिशियलाइज़ेशन" नामक नई अवधारणा नहीं बनानी चाहिए।
4- नेस्टेड अनाम कक्षाओं को बनाने में दो ब्रेसिज़ के साथ कुछ नहीं करना है:
मैं एक तर्क से सहमत नहीं हूं कि आप बहुत अधिक अनाम कक्षाएं बनाते हैं। आप उन्हें एक इनिशियलाइज़ेशन ब्लॉक के कारण नहीं बना रहे हैं, बल्कि सिर्फ इसलिए कि आप उन्हें बनाते हैं। वे तब भी बनाए जाएंगे जब आपने दो ब्रेसिज़ इनिशियलाइज़ेशन का उपयोग नहीं किया था, इसलिए वे समस्याएं बिना इनिशियलाइज़ेशन के भी हो जाएंगी ... इनिशियलाइज़ेशन वह कारक नहीं है जो इनिशियलाइज़्ड ऑब्जेक्ट बनाता है।
इसके अतिरिक्त हमें इस गैर-मौजूद चीज़ "डबल ब्रेस इनिशियलाइज़ेशन" या सामान्य एक ब्रैकेट इनिशियलाइज़ेशन का उपयोग करके बनाई गई समस्या के बारे में बात नहीं करनी चाहिए, क्योंकि वर्णित समस्याएं केवल अनाम वर्ग बनाने के कारण मौजूद हैं, इसलिए इसका मूल प्रश्न से कोई लेना-देना नहीं है। लेकिन सभी उत्तर पाठकों को यह आभास कराते हैं कि यह गुमनाम वर्गों के निर्माण का दोष नहीं है, बल्कि इस बुराई (अस्तित्वहीन) चीज को "डबल ब्रेस इनिशियलाइज़ेशन" कहा जाता है।
डबल ब्रेस इनिशियलाइज़ेशन के सभी नकारात्मक प्रभावों से बचने के लिए, जैसे:
अगले काम करो:
उदाहरण:
public class MyClass {
public static class Builder {
public int first = -1 ;
public double second = Double.NaN;
public String third = null ;
public MyClass create() {
return new MyClass(first, second, third);
}
}
protected final int first ;
protected final double second;
protected final String third ;
protected MyClass(
int first ,
double second,
String third
) {
this.first = first ;
this.second= second;
this.third = third ;
}
public int first () { return first ; }
public double second() { return second; }
public String third () { return third ; }
}
उपयोग:
MyClass my = new MyClass.Builder(){{ first = 1; third = "3"; }}.create();
लाभ:
नुकसान:
और, परिणामस्वरूप, हमारे पास सबसे सरल जावा बिल्डर पैटर्न है।
जीथब पर सभी नमूने देखें: जावा-एसएफ-बिल्डर-सरल-उदाहरण
यह - अन्य उपयोगों के बीच - संग्रह को आरंभ करने के लिए एक शॉर्टकट है। और अधिक जानें ...
संग्रह को आरंभ करने के लिए आप कुछ जावा स्टेटमेंट को लूप के रूप में रख सकते हैं:
List<Character> characters = new ArrayList<Character>() {
{
for (char c = 'A'; c <= 'E'; c++) add(c);
}
};
Random rnd = new Random();
List<Integer> integers = new ArrayList<Integer>() {
{
while (size() < 10) add(rnd.nextInt(1_000_000));
}
};
जैसा कि @Lukas Eder द्वारा बताया गया है कि संग्रह के दोहरे ब्रेसिज़ की शुरुआत से बचा जाना चाहिए।
यह एक अनाम आंतरिक वर्ग बनाता है, और चूंकि सभी आंतरिक वर्ग माता-पिता के उदाहरण के संदर्भ में इसे रख सकते हैं - और 99% संभावना है - कचरा संग्रहण को रोकें यदि इन संग्रह वस्तुओं को केवल घोषित करने की तुलना में अधिक वस्तुओं द्वारा संदर्भित किया जाता है।
जावा 9 सुविधा तरीकों शुरू की है List.of
, Set.of
और Map.of
है, जो बजाय प्रयोग किया जाना चाहिए। वे डबल-ब्रेस इनिशियलाइज़र की तुलना में तेज़ और अधिक कुशल हैं।
पहला ब्रेस एक नया बेनामी क्लास बनाता है और ब्रेस का दूसरा सेट स्टैटिक ब्लॉक की तरह एक इंस्टेंस इनिशियलाइज़र बनाता है।
जैसे दूसरों ने इशारा किया है, इसका उपयोग करना सुरक्षित नहीं है।
हालाँकि, आप इस विकल्प का उपयोग संग्रह को आरंभ करने के लिए हमेशा कर सकते हैं।
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> list = List.of("A", "B", "C");
यह फ़्लैश और vbscript में लोकप्रिय कीवर्ड के समान ही प्रतीत होगा। यह जो this
कुछ भी नहीं है उसे बदलने की एक विधि है ।
this
है। वाक्यविन्यास सिर्फ एक अनाम वर्ग बनाता है (इसलिए किसी भी संदर्भ को this
उस नए अनाम वर्ग की वस्तु के रूप में संदर्भित किया जाएगा), और फिर {...}
नए बनाए गए इंस्टेंस को आरंभीकृत करने के लिए एक शुरुआती ब्लॉक का उपयोग करता है ।