जावा की क्षमता "डबल ब्रेस इनिशियलाइज़ेशन"?


823

में जावा के छिपे हुए विशेषताएं शीर्ष जवाब का उल्लेख है धनुकोष्ठक प्रारंभ , एक साथ बहुत आकर्षक वाक्य रचना:

Set<String> flavors = new HashSet<String>() {{
    add("vanilla");
    add("strawberry");
    add("chocolate");
    add("butter pecan");
}};

यह मुहावरा एक गुमनाम आंतरिक वर्ग बनाता है जिसमें सिर्फ एक उदाहरण इनिशलाइज़र है, जो "किसी भी [...] विधियों का उपयोग कर सकता है।

मुख्य प्रश्न: क्या यह उतना ही अक्षम है जितना यह लगता है? क्या इसका उपयोग एकबारगी आरंभ तक सीमित होना चाहिए? (और जाहिर है दिखावा!)

दूसरा प्रश्न: नए हैशसेट का उपयोग "इस" उदाहरण के इनिशलाइज़र में किया जाना चाहिए ... क्या कोई तंत्र पर प्रकाश डाल सकता है?

तीसरा प्रश्न: क्या यह मुहावरा भी उत्पादन कोड में उपयोग करने के लिए अस्पष्ट है?

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

प्रश्न (1) पर, उत्पन्न कोड जल्दी से चलना चाहिए। अतिरिक्त .class फ़ाइलें जार फ़ाइल अव्यवस्था का कारण बनती हैं, और धीमी गति से प्रोग्राम स्टार्टअप को थोड़ा सा (उस मापने के लिए @coobird के लिए धन्यवाद)। @ थिलो ने बताया कि कचरा संग्रह प्रभावित हो सकता है, और अतिरिक्त भार वाले वर्गों के लिए मेमोरी लागत कुछ मामलों में एक कारक हो सकती है।

प्रश्न (2) मेरे लिए सबसे दिलचस्प निकला। अगर मैं जवाबों को समझता हूं, तो डीबीआई में जो हो रहा है, वह यह है कि अनाम आंतरिक वर्ग नए ऑपरेटर द्वारा बनाई जा रही वस्तु के वर्ग का विस्तार करता है, और इसलिए इसका निर्माण किया जा रहा उदाहरण संदर्भित "यह" मान है। बहुत साफ़।

कुल मिलाकर, DBI ने एक बौद्धिक जिज्ञासा के रूप में मुझ पर प्रहार किया। Coobird और अन्य बताते हैं कि आप Arrays.asList, varargs के तरीकों, Google संग्रह और प्रस्तावित Java 7 संग्रह शाब्दिक के साथ समान प्रभाव प्राप्त कर सकते हैं। नई JVM स्कैला, JRuby, और ग्रूवी जैसी भाषाएं भी सूची निर्माण के लिए संक्षिप्त अधिसूचनाएं प्रदान करती हैं, और जावा के साथ अच्छी तरह से हस्तक्षेप करती हैं। यह देखते हुए कि डीबीआई क्लासपाट को बंद कर देता है, क्लास लोडिंग को थोड़ा धीमा कर देता है, और कोड को अधिक अस्पष्ट बनाता है, मैं शायद इससे दूर हटूंगा। हालाँकि, मैं इसे एक ऐसे दोस्त पर बसाने की योजना बना रहा हूँ, जो अपने SCJP को प्राप्त कर चुका है और जावा शब्दार्थ के बारे में अच्छे स्वभाव वाले जत्थों से प्यार करता है! ;-) सभी को धन्यवाद!

7/2017: बाल्डुंग में डबल ब्रेस आरंभीकरण का अच्छा सारांश है और इसे एक विरोधी पैटर्न मानता है।

12/2017: @Basil Bourque ध्यान दें कि नए जावा 9 में आप कह सकते हैं:

Set<String> flavors = Set.of("vanilla", "strawberry", "chocolate", "butter pecan");

यह निश्चित रूप से जाने का रास्ता है। यदि आप पहले के संस्करण के साथ फंस गए हैं, तो Google संग्रह 'ImmutableSet पर एक नज़र डालें ।


33
यहाँ जो कोड की गंध मुझे दिख रही है, वह यह है कि भोले पाठक flavorsएक होने की उम्मीद करेंगे HashSet, लेकिन अफसोस कि यह एक गुमनाम उपवर्ग है।
एलाजार लीबोविच

6
यदि आप प्रदर्शन को लोड करने के बजाय चलाने पर विचार करते हैं तो कोई अंतर नहीं है, मेरा उत्तर देखें।
पीटर लॉरी

4
मुझे लगता है कि आपने एक सारांश तैयार किया है, मुझे लगता है कि यह आप दोनों के लिए समझ और समुदाय को बढ़ाने के लिए एक सार्थक अभ्यास है।
पैट्रिक मर्फी

3
यह मेरी राय में अस्पष्ट नहीं है। पाठकों को पता होना चाहिए कि एक डबल ... ओ रुको, @ElazarLeibovich ने पहले ही अपनी टिप्पणी में कहा था । डबल ब्रेस इनिशलाइज़र खुद एक भाषा निर्माण के रूप में मौजूद नहीं है, यह सिर्फ एक अनाम उपवर्ग और एक उदाहरण इनिशलाइज़र का संयोजन है। केवल एक चीज यह है कि लोगों को इसके बारे में जागरूक होने की आवश्यकता है।
एमसी सम्राट

8
जावा 9 कुछ स्थितियों में DCI के उपयोग की जगह ले सकने वाले अचल सेट स्टैटिक फैक्ट्री मेथड प्रदान करता है:Set<String> flavors = Set.of( "vanilla" , "strawberry" , "chocolate" , "butter pecan" ) ;
बेसिल बोर्क

जवाबों:


607

यहाँ समस्या है जब मैं भी गुमनाम आंतरिक वर्गों के साथ दूर किया जाता है:

2009/05/27  16:35             1,602 DemoApp2$1.class
2009/05/27  16:35             1,976 DemoApp2$10.class
2009/05/27  16:35             1,919 DemoApp2$11.class
2009/05/27  16:35             2,404 DemoApp2$12.class
2009/05/27  16:35             1,197 DemoApp2$13.class

/* snip */

2009/05/27  16:35             1,953 DemoApp2$30.class
2009/05/27  16:35             1,910 DemoApp2$31.class
2009/05/27  16:35             2,007 DemoApp2$32.class
2009/05/27  16:35               926 DemoApp2$33$1$1.class
2009/05/27  16:35             4,104 DemoApp2$33$1.class
2009/05/27  16:35             2,849 DemoApp2$33.class
2009/05/27  16:35               926 DemoApp2$34$1$1.class
2009/05/27  16:35             4,234 DemoApp2$34$1.class
2009/05/27  16:35             2,849 DemoApp2$34.class

/* snip */

2009/05/27  16:35               614 DemoApp2$40.class
2009/05/27  16:35             2,344 DemoApp2$5.class
2009/05/27  16:35             1,551 DemoApp2$6.class
2009/05/27  16:35             1,604 DemoApp2$7.class
2009/05/27  16:35             1,809 DemoApp2$8.class
2009/05/27  16:35             2,022 DemoApp2$9.class

ये सभी वर्ग हैं जो तब उत्पन्न हुए थे जब मैं एक साधारण आवेदन कर रहा था, और अनाम आंतरिक कक्षाओं के प्रचुर मात्रा में उपयोग किया गया था - प्रत्येक कक्षा को एक अलग classफ़ाइल में संकलित किया जाएगा ।

"डबल ब्रेस इनिशियलाइज़ेशन", जैसा कि पहले ही उल्लेख किया गया है, उदाहरण के इनिशियलाइज़ेशन ब्लॉक के साथ एक अनाम आंतरिक वर्ग है, जिसका अर्थ है कि प्रत्येक "इनिशियलाइज़ेशन" के लिए एक नया वर्ग बनाया जाता है, जो कि आमतौर पर एक एकल ऑब्जेक्ट बनाने के उद्देश्य से होता है।

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

ऐसा लगता है जैसे डबल-ब्रेस इनिशियलाइज़ेशन का उपयोग करते समय ओवरहेड का एक सा हिस्सा होता है, इसलिए इसके साथ बहुत अधिक ओवरबोर्ड जाना शायद ऐसा अच्छा विचार नहीं है। लेकिन जैसा कि एडी ने टिप्पणियों में उल्लेख किया है, यह प्रभाव के बारे में बिल्कुल सुनिश्चित होना संभव नहीं है।


सिर्फ संदर्भ के लिए, डबल ब्रेस इनिशियलाइज़ेशन निम्नलिखित है:

List<String> list = new ArrayList<String>() {{
    add("Hello");
    add("World!");
}};

यह जावा की एक "छिपी हुई" विशेषता की तरह दिखता है, लेकिन यह सिर्फ एक फिर से लिखना है:

List<String> list = new ArrayList<String>() {

    // Instance initialization block
    {
        add("Hello");
        add("World!");
    }
};

तो यह मूल रूप से एक उदाहरण इनिशियलाइज़ेशन ब्लॉक है जो एक अनाम आंतरिक वर्ग का हिस्सा है ।


प्रोजेक्ट सिक्के के लिए जोशुआ बलोच का कलेक्शन लिटरल्स का प्रस्ताव :

List<Integer> intList = [1, 2, 3, 4];

Set<String> strSet = {"Apple", "Banana", "Cactus"};

Map<String, Integer> truthMap = { "answer" : 42 };

अफसोस की बात है कि इसने जावा 7 या 8 में अपना रास्ता नहीं बनाया और अनिश्चित काल के लिए इसे बंद कर दिया गया।


प्रयोग

यहाँ मैंने जो सरल परीक्षण किया है, वह है - ArrayListतत्वों के साथ 1000 एस बनाएं "Hello"और "World!"उन्हें addदो तरीकों का उपयोग करके विधि के माध्यम से जोड़ा गया :

विधि 1: डबल ब्रेस इनिशियलाइज़ेशन

List<String> l = new ArrayList<String>() {{
  add("Hello");
  add("World!");
}};

विधि 2: का दृष्टांत एक ArrayListऔरadd

List<String> l = new ArrayList<String>();
l.add("Hello");
l.add("World!");

मैंने दो तरीकों का उपयोग करके 1000 आरंभीकरण करने के लिए एक जावा स्रोत फ़ाइल लिखने के लिए एक सरल प्रोग्राम बनाया:

टेस्ट 1:

class Test1 {
  public static void main(String[] s) {
    long st = System.currentTimeMillis();

    List<String> l0 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    List<String> l1 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    /* snip */

    List<String> l999 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    System.out.println(System.currentTimeMillis() - st);
  }
}

टेस्ट 2:

class Test2 {
  public static void main(String[] s) {
    long st = System.currentTimeMillis();

    List<String> l0 = new ArrayList<String>();
    l0.add("Hello");
    l0.add("World!");

    List<String> l1 = new ArrayList<String>();
    l1.add("Hello");
    l1.add("World!");

    /* snip */

    List<String> l999 = new ArrayList<String>();
    l999.add("Hello");
    l999.add("World!");

    System.out.println(System.currentTimeMillis() - st);
  }
}

कृपया ध्यान दें, कि 1000 ArrayLists और 1000 अनाम आंतरिक वर्गों को शुरू करने के लिए बीता हुआ समय का ArrayListउपयोग करके जाँच की जाती है System.currentTimeMillis, इसलिए टाइमर में बहुत अधिक रिज़ॉल्यूशन नहीं है। मेरे विंडोज सिस्टम पर, रिज़ॉल्यूशन लगभग 15-16 मिलीसेकंड है।

दो परीक्षणों के 10 रन के परिणाम निम्नलिखित थे:

Test1 Times (ms)           Test2 Times (ms)
----------------           ----------------
           187                          0
           203                          0
           203                          0
           188                          0
           188                          0
           187                          0
           203                          0
           188                          0
           188                          0
           203                          0

जैसा कि देखा जा सकता है, डबल ब्रेस इनिशियलाइज़ेशन में लगभग 190 एमएस का ध्यान देने योग्य निष्पादन समय है।

इस बीच, ArrayListइनिशियलाइज़ेशन का निष्पादन समय 0 एमएस था। बेशक, टाइमर रिज़ॉल्यूशन को ध्यान में रखा जाना चाहिए, लेकिन यह 15 एमएस से कम होने की संभावना है।

तो, दो तरीकों के निष्पादन समय में एक उल्लेखनीय अंतर प्रतीत होता है। ऐसा प्रतीत होता है कि दो आरंभीकरण विधियों में वास्तव में कुछ ओवरहेड है।

और हाँ, दोहरे ब्रेस आरंभीकरण परीक्षण कार्यक्रम .classको संकलित करके उत्पन्न 1000 फाइलें थीं Test1


10
"शायद" ऑपरेटिव शब्द है। जब तक मापा नहीं जाता है, प्रदर्शन के बारे में कोई भी बयान सार्थक नहीं है।
इंस्टा हंटर

16
आपने ऐसा शानदार काम किया है, मैं शायद ही यह कहना चाहता हूं, लेकिन टेस्ट 1 बार क्लास के भार से हावी हो सकता है। यह देखना दिलचस्प होगा कि कोई व्यक्ति प्रत्येक परीक्षण के एक ही उदाहरण को लूप में 1,000 बार कहता है, फिर इसे 1,000 या 10,000 बार लूप के लिए एक सेकंड में फिर से चलाएं और समय के अंतर (System.nanoTime ()) का प्रिंट आउट लें। लूप के लिए पहले सभी वार्म अप प्रभाव (जेआईटी, क्लास लोड, जैसे) को पा लेना चाहिए। दोनों परीक्षण हालांकि अलग-अलग उपयोग-मामलों को मॉडल करते हैं। मैं इसे कल काम पर चलाने की कोशिश करूंगा।
जिम फेरनस

8
@ जैम फेरेंस: मैं काफी निश्चित हूं कि टेस्ट 1 बार वर्ग भार से हैं। लेकिन, दोहरे ब्रेस आरंभीकरण का उपयोग करने का परिणाम वर्ग भार से सामना करना पड़ रहा है। मेरा मानना ​​है कि डबल ब्रेस इनिट के लिए ज्यादातर उपयोग के मामले हैं। एक बार के आरंभीकरण के लिए है, परीक्षण इस प्रकार के आरंभीकरण के एक विशिष्ट उपयोग के मामले में स्थितियों के करीब है। मेरा मानना ​​है कि प्रत्येक परीक्षण के कई पुनरावृत्तियों निष्पादन समय अंतराल को छोटा कर देगा।
कोबर्ड

73
यह क्या साबित करता है कि ए) डबल-ब्रेस इनिशियलाइज़ेशन धीमा है, और बी) भले ही आप इसे 1000 बार करते हैं, आप शायद अंतर को नोटिस नहीं करेंगे। और ऐसा नहीं है कि यह आंतरिक लूप में अड़चन हो सकती है। यह बहुत काम पर एक बार जुर्माना लगाता है।
माइकल मायर्स

15
यदि DBI कोड का उपयोग अधिक पठनीय या अभिव्यंजक बनाता है, तो इसका उपयोग करें। तथ्य यह है कि यह थोड़ा बढ़ जाता है जिस काम को करने के लिए जेवीएम को एक मान्य तर्क नहीं है, अपने आप में, इसके खिलाफ। अगर ऐसा था, तो हमें अतिरिक्त सहायक विधियों / कक्षाओं के बारे में भी चिंतित होना चाहिए, कम विधियों के साथ विशाल कक्षाओं को प्राथमिकता देना ...
Rogério

105

इस दृष्टिकोण की एक संपत्ति जिसे अभी तक इंगित नहीं किया गया है, वह यह है कि क्योंकि आप आंतरिक कक्षाएं बनाते हैं, पूरी युक्त कक्षा इसके दायरे में कैप्चर की जाती है। इसका मतलब यह है कि जब तक आपका सेट जीवित है, तब तक यह पॉइंटर को रखने वाले उदाहरण ( this$0) को बनाए रखेगा और इसे कचरा-एकत्र होने से रखेगा, जो एक मुद्दा हो सकता है।

यह और यह तथ्य कि एक नया वर्ग पहली बार में निर्मित हो जाता है, भले ही एक नियमित हैशसेट ठीक काम करेगा (या इससे भी बेहतर), मुझे इस निर्माण का उपयोग नहीं करना चाहता (भले ही मैं वाक्यात्मक चीनी के लिए लंबे समय तक)।

दूसरा सवाल: नए हैशसेट का उपयोग "इस" उदाहरण के इनिशलाइज़र में होना चाहिए ... क्या कोई तंत्र पर प्रकाश डाल सकता है? मैं "जायके" के लिए "जायके" को संदर्भित करता हूं।

यह सिर्फ यह है कि आंतरिक कक्षाएं कैसे काम करती हैं। वे अपने स्वयं के प्राप्त करते हैं this, लेकिन उनके पास मूल उदाहरण के लिए संकेत भी होते हैं, ताकि आप युक्त वस्तु पर भी तरीकों को कॉल कर सकें। एक नामकरण संघर्ष के मामले में, आंतरिक वर्ग (आपके मामले में हैशसेट) पूर्वता लेता है, लेकिन आप बाहरी विधि प्राप्त करने के लिए एक क्लासनाम के साथ "यह" उपसर्ग कर सकते हैं।

public class Test {

    public void add(Object o) {
    }

    public Set<String> makeSet() {
        return new HashSet<String>() {
            {
              add("hello"); // HashSet
              Test.this.add("hello"); // outer instance 
            }
        };
    }
}

अनाम उपवर्ग को बनाए जाने पर स्पष्ट होने के लिए, आप वहां के तरीकों को भी परिभाषित कर सकते हैं। उदाहरण के लिए ओवरराइडHashSet.add()

    public Set<String> makeSet() {
        return new HashSet<String>() {
            {
              add("hello"); // not HashSet anymore ...
            }

            @Override
            boolean add(String s){

            }

        };
    }

5
युक्त वर्ग के छिपे हुए संदर्भ पर बहुत अच्छा बिंदु। मूल उदाहरण में, उदाहरण इनिशलाइज़र नए हैशसेट <स्ट्रिंग> के ऐड () विधि को बुला रहा है, न कि Test.this.add ()। इससे मुझे पता चलता है कि कुछ और हो रहा है। क्या हैशसेट <स्ट्रिंग> के लिए एक अनाम आंतरिक वर्ग है, जैसा कि नाथन किचन बताता है?
जिम फेरेंस

डेटासट्रक्चर के क्रमांकन शामिल होने पर युक्त वर्ग का संदर्भ भी खतरनाक हो सकता है। युक्त वर्ग को भी क्रमबद्ध किया जाएगा और इस प्रकार सीरियल किया जाना चाहिए। इससे अस्पष्ट त्रुटियां हो सकती हैं।
बस

56

हर बार जब कोई डबल ब्रेस इनिशियलाइज़ेशन का उपयोग करता है, तो एक बिल्ली का बच्चा मारा जाता है।

वाक्यविन्यास असामान्य होने के अलावा और वास्तव में मुहावरेदार नहीं है (स्वाद बहस योग्य है, निश्चित रूप से), आप अनावश्यक रूप से अपने आवेदन में दो महत्वपूर्ण समस्याएं पैदा कर रहे हैं, जिनके बारे में मैंने हाल ही में यहां और अधिक विस्तार से ब्लॉग किया है

1. आप बहुत अधिक अनाम कक्षाएं बना रहे हैं

हर बार जब आप डबल ब्रेस इनिशियलाइज़ेशन का उपयोग करते हैं तो एक नया वर्ग बनाया जाता है। उदाहरण के लिए:

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 बार करते हैं ... तो बस "सिंटेक्स शुगर" के लिए मेमोरी को ढेर कर दें?

2. आप संभावित रूप से एक मेमोरी लीक बना रहे हैं!

यदि आप उपरोक्त कोड लेते हैं और उस नक्शे को किसी विधि से वापस करते हैं, तो उस विधि के कॉलर बहुत ही भारी संसाधनों को पकड़े हुए हो सकते हैं जो कचरा एकत्र नहीं कर सकते हैं। निम्नलिखित उदाहरण पर विचार करें:

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/ से छवि

3. आप यह दिखावा कर सकते हैं कि जावा में मानचित्र शाब्दिक हैं

आपके वास्तविक प्रश्न का उत्तर देने के लिए, लोग इस वाक्यविन्यास का उपयोग यह दिखाने के लिए कर रहे हैं कि जावा के पास मौजूदा शाब्दिक साहित्य के समान मानचित्र शाब्दिक जैसा कुछ है:

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};

कुछ लोगों को यह वाक्यात्मक रूप से उत्तेजक लग सकता है।


7
बिल्ली के बच्चे बचाओ! अच्छा उत्तर!
Aris2World

36

निम्नलिखित परीक्षण वर्ग लेना:

public class Test {
  public void test() {
    Set<String> flavors = new HashSet<String>() {{
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
    }};
  }
}

और फिर कक्षा फ़ाइल को विघटित करते हुए, मैं देखता हूं:

public class Test {
  public void test() {
    java.util.Set flavors = new HashSet() {

      final Test this$0;

      {
        this$0 = Test.this;
        super();
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
      }
    };
  }
}

यह मेरे लिए बहुत अक्षम नहीं दिखता है। अगर मुझे इस तरह की चीज़ के लिए प्रदर्शन की चिंता थी, तो मैं इसे प्रोफ़ाइल करता। और आपके प्रश्न # 2 का उत्तर उपरोक्त कोड द्वारा दिया गया है: आप अपने भीतर के वर्ग के लिए एक अंतर्निहित कंस्ट्रक्टर (और उदाहरण इनिशलाइज़र) के अंदर हैं, इसलिए " this" इस आंतरिक वर्ग को संदर्भित करता है।

हां, यह सिंटैक्स अस्पष्ट है, लेकिन एक टिप्पणी अस्पष्ट सिंटैक्स उपयोग को स्पष्ट कर सकती है। सिंटैक्स को स्पष्ट करने के लिए, अधिकांश लोग एक स्टेटिक इनिशियलाइज़र ब्लॉक (JLS 8.7 Static Initializers) से परिचित हैं:

public class Sample1 {
    private static final String someVar;
    static {
        String temp = null;
        ..... // block of code setting temp
        someVar = temp;
    }
}

आप staticकंस्ट्रक्टर उपयोग के लिए एक समान वाक्यविन्यास ("शब्द के बिना ") का भी उपयोग कर सकते हैं (जेएलएस 8.6 इंस्टेंस इनिशियलाइज़र), हालांकि मैंने इसे उत्पादन कोड में कभी नहीं देखा है। यह बहुत कम ज्ञात है।

public class Sample2 {
    private final String someVar;

    // This is an instance initializer
    {
        String temp = null;
        ..... // block of code setting temp
        someVar = temp;
    }
}

यदि आपके पास डिफ़ॉल्ट कंस्ट्रक्टर नहीं है, तो कंपाइलर द्वारा कोड को ब्लॉक {और }कंस्ट्रक्टर में बदल दिया जाता है। इसे ध्यान में रखते हुए, डबल ब्रेस कोड को खोलें:

public void test() {
  Set<String> flavors = new HashSet<String>() {
      {
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
      }
  };
}

आंतरिक-सबसे ब्रेसिज़ के बीच कोड का ब्लॉक कंपाइलर द्वारा एक कंस्ट्रक्टर में बदल दिया जाता है। बाहरी-सबसे ब्रेसिज़ अनाम आंतरिक वर्ग का परिसीमन करते हैं। यह सब कुछ गैर-अनाम बनाने का अंतिम चरण लेने के लिए:

public void test() {
  Set<String> flavors = new MyHashSet();
}

class MyHashSet extends HashSet<String>() {
    public MyHashSet() {
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
    }
}

आरंभिक उद्देश्यों के लिए, मैं कहूंगा कि कोई भी उपरि नहीं है (या इतना छोटा कि इसे उपेक्षित किया जा सके)। हालाँकि, हर उपयोग के flavorsखिलाफ नहीं HashSetबल्कि इसके खिलाफ जाना होगा MyHashSet। इसके लिए शायद एक छोटा (और काफी संभवतः नगण्य) ओवरहेड है। लेकिन फिर, इससे पहले कि मैं इसके बारे में चिंतित हो, मैं इसे प्रोफाइल करूंगा।

फिर से, आपके प्रश्न # 2 पर, उपरोक्त कोड डबल ब्रेस इनिशियलाइज़ेशन का तार्किक और स्पष्ट समकक्ष है, और यह स्पष्ट thisकरता है कि " " कहां संदर्भित होता है: आंतरिक वर्ग तक फैली हुई है HashSet

यदि आपके पास उदाहरण इनिशियलाइज़र के विवरण के बारे में प्रश्न हैं, तो जेएलएस प्रलेखन में विवरण देखें ।


एडी, बहुत अच्छी व्याख्या। यदि JVM बाइट कोड डिकम्पोजिशन की तरह साफ हैं, तो निष्पादन की गति काफी तेज होगी, हालांकि मैं अतिरिक्त .class फ़ाइल अव्यवस्था के बारे में कुछ चिंतित हूं। मैं अभी भी उत्सुक हूं कि इंस्ट्रूमेंट इंट्रूजर का कंस्ट्रक्टर "इसे" नए हैशसेट <स्ट्रिंग> उदाहरण के रूप में क्यों देखता है, न कि टेस्ट इंस्टेंस के रूप में। क्या यह मुहावरे का समर्थन करने के लिए नवीनतम जावा लैंग्वेज स्पेसिफिकेशन में स्पष्ट रूप से निर्दिष्ट व्यवहार है?
जिम फ्राँस

मैंने अपना उत्तर अपडेट कर दिया। मैंने टेस्ट क्लास के बॉयलरप्लेट को छोड़ दिया, जिससे भ्रम पैदा हुआ। मैंने चीजों को और अधिक स्पष्ट करने के लिए इसे अपने उत्तर में डाल दिया। मैं इस मुहावरे में प्रयुक्त उदाहरण इनिशियल ब्लॉक्स के लिए JLS खंड का भी उल्लेख करता हूँ।
एडी

1
@ जय "यह" की व्याख्या कोई विशेष मामला नहीं है; यह केवल अंतरतम संलग्नक वर्ग के उदाहरण को संदर्भित करता है, जो हैशसेट <स्ट्रिंग> का अनाम उपवर्ग है।
नाथन किचन

साढ़े चार साल बाद कूदने के लिए क्षमा करें। लेकिन विघटित वर्ग फ़ाइल (आपका दूसरा कोड ब्लॉक) के बारे में अच्छी बात यह है कि यह वैध जावा नहीं है! इसमें super()निहित निर्माणकर्ता की दूसरी पंक्ति के रूप में है, लेकिन इसे पहले आना है। (मैंने इसका परीक्षण किया है, और यह संकलित नहीं होगा।)
chiastic-Security

1
@ chiastic- सुरक्षा: कभी-कभी डिकम्पाइलर्स ऐसा कोड उत्पन्न करते हैं जो संकलन नहीं करेगा।
एडी

35

रिसाव होने का खतरा

मैंने झंकार करने का फैसला किया है। प्रदर्शन प्रभाव में शामिल हैं: डिस्क ऑपरेशन + अनज़िप (जार के लिए), वर्ग सत्यापन, पर्म-जीन स्पेस (सन के हॉटस्पॉट जेवीएम के लिए)। हालांकि, सबसे खराब: यह लीक प्रवण है। तुम बस नहीं लौट सकते।

Set<String> getFlavors(){
  return Collections.unmodifiableSet(flavors)
}

इसलिए यदि सेट किसी अलग क्लास लोडर द्वारा लोड किए गए किसी अन्य भाग में भाग जाता है और वहां एक संदर्भ रखा जाता है, तो कक्षाओं + क्लास लोडर का पूरा पेड़ लीक हो जाएगा। कि बचने के लिए, HashMap की एक प्रति, आवश्यक है new LinkedHashSet(new ArrayList(){{add("xxx);add("yyy");}})। इतना प्यारा कोई और नहीं। मैं मुहावरे का उपयोग नहीं करता, स्वयं, इसके बजाय यह पसंद है new LinkedHashSet(Arrays.asList("xxx","YYY"));


3
सौभाग्य से, जावा 8 के रूप में, PermGen अब एक चीज नहीं है। अभी भी एक प्रभाव है, मुझे लगता है, लेकिन संभावित रूप से बहुत अस्पष्ट त्रुटि संदेश के साथ कोई भी नहीं।
जॉय

2
@ जॉय, शून्य अंतर बनाता है अगर मेमोरी को सीधे जीसी (परमिट जीन) द्वारा प्रबंधित किया जाता है या नहीं। मेटासैपेस में एक रिसाव अभी भी एक रिसाव है, जब तक कि मेटा सीमित नहीं है लिनक्स में ओओएम_किलर जैसे सामान द्वारा एक ओओएम (परमिट जीन से बाहर) नहीं होगा।
bestsss

19

लोड हो रहा है कई कक्षाएं शुरुआत में कुछ मिलीसेकंड जोड़ सकती हैं। यदि स्टार्टअप इतना महत्वपूर्ण नहीं है और आप स्टार्टअप के बाद कक्षाओं की दक्षता को देख रहे हैं तो कोई अंतर नहीं है।

package vanilla.java.perfeg.doublebracket;

import java.util.*;

/**
 * @author plawrey
 */
public class DoubleBracketMain {
    public static void main(String... args) {
        final List<String> list1 = new ArrayList<String>() {
            {
                add("Hello");
                add("World");
                add("!!!");
            }
        };
        List<String> list2 = new ArrayList<String>(list1);
        Set<String> set1 = new LinkedHashSet<String>() {
            {
                addAll(list1);
            }
        };
        Set<String> set2 = new LinkedHashSet<String>();
        set2.addAll(list1);
        Map<Integer, String> map1 = new LinkedHashMap<Integer, String>() {
            {
                put(1, "one");
                put(2, "two");
                put(3, "three");
            }
        };
        Map<Integer, String> map2 = new LinkedHashMap<Integer, String>();
        map2.putAll(map1);

        for (int i = 0; i < 10; i++) {
            long dbTimes = timeComparison(list1, list1)
                    + timeComparison(set1, set1)
                    + timeComparison(map1.keySet(), map1.keySet())
                    + timeComparison(map1.values(), map1.values());
            long times = timeComparison(list2, list2)
                    + timeComparison(set2, set2)
                    + timeComparison(map2.keySet(), map2.keySet())
                    + timeComparison(map2.values(), map2.values());
            if (i > 0)
                System.out.printf("double braced collections took %,d ns and plain collections took %,d ns%n", dbTimes, times);
        }
    }

    public static long timeComparison(Collection a, Collection b) {
        long start = System.nanoTime();
        int runs = 10000000;
        for (int i = 0; i < runs; i++)
            compareCollections(a, b);
        long rate = (System.nanoTime() - start) / runs;
        return rate;
    }

    public static void compareCollections(Collection a, Collection b) {
        if (!a.equals(b) && a.hashCode() != b.hashCode() && !a.toString().equals(b.toString()))
            throw new AssertionError();
    }
}

प्रिंट

double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 34 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns

2
इसके अलावा कोई अंतर नहीं है कि यदि डीबीआई का अत्यधिक उपयोग किया जाता है तो आपका पर्मजेन स्पेस वाष्पित हो जाएगा। कम से कम, यह तब तक रहेगा जब तक कि आप पेर्मेन स्पेस के क्लास-अनलोडिंग और कचरा-संग्रह की अनुमति देने के लिए कुछ अस्पष्ट जेवीएम विकल्प सेट नहीं करेंगे । सर्वर-साइड भाषा के रूप में जावा की व्यापकता को देखते हुए, मेमोरी / पर्मगेन वारंट को कम से कम एक उल्लेखित करता है।
आरोह

1
@ यह एक अच्छा बिंदु है। मैं स्वीकार करता हूं कि जावा में काम करने के 16 वर्षों में मैंने कभी भी ऐसी प्रणाली पर काम नहीं किया है जहां आपको पर्मगेन (या मेटासैपेस) को ट्यून करना पड़ा हो, जिन प्रणालियों के लिए मैंने कोड के आकार पर काम किया है उन्हें हमेशा यथोचित रूप से छोटा रखा गया था।
पीटर लॉरी

2
शर्तों compareCollectionsके ||बजाय के साथ संयुक्त में नहीं होना चाहिए &&? प्रयोग &&न केवल शब्दार्थिक रूप से गलत लगता है, यह प्रदर्शन को मापने के इरादे का प्रतिकार करता है, क्योंकि केवल पहली स्थिति का ही परीक्षण किया जाएगा। इसके अलावा, एक स्मार्ट ऑप्टिमाइज़र यह पहचान सकता है कि पुनरावृत्तियों के दौरान स्थितियां कभी नहीं बदलेंगी।
होल्गर

@aroth सिर्फ एक अद्यतन के रूप में: जावा 8 के बाद से वीएम अब किसी भी परमिट-जीन का उपयोग नहीं करता है।
एंजेल ओ 'स्फीयर

16

सेट बनाने के लिए आप डबल-ब्रेस इनिशियलाइज़ेशन के बजाय एक वैरगेज़ फ़ैक्टरी विधि का उपयोग कर सकते हैं:

public static Set<T> setOf(T ... elements) {
    return new HashSet<T>(Arrays.asList(elements));
}

Google संग्रह लाइब्रेरी में इस तरह की बहुत सारी सुविधा विधियां हैं, साथ ही साथ अन्य उपयोगी कार्यक्षमता का भार भी है।

मुहावरे की अस्पष्टता के लिए, मैं इसका सामना करता हूं और हर समय उत्पादन कोड में इसका उपयोग करता हूं। मुझे प्रोग्रामर के बारे में अधिक चिंता होगी जो मुहावरे से भ्रमित हो जाते हैं उन्हें उत्पादन कोड लिखने की अनुमति दी जाती है।


हा! ;-) मैं वास्तव में 1.2 दिनों से जावा की ओर लौटने एक रिप वैन विंकल हूँ (मैं कम से VoiceXML आवाज वेब ब्राउज़र लिखा evolution.voxeo.com जावा में)। यह मज़ेदार अधिगम है जेनरिक, पैरामीटर किए गए प्रकार, संग्रह, java.util.concurrent, लूप सिंटैक्स के लिए नया, आदि। यह अब एक बेहतर भाषा है। आपकी बात के लिए, भले ही DBI के पीछे का तंत्र पहली बार में अस्पष्ट लग रहा हो, कोड का अर्थ बहुत स्पष्ट होना चाहिए।
जिम फेरेंस

10

दक्षता एक तरफ, मैं शायद ही कभी खुद को इकाई परीक्षणों के बाहर घोषणात्मक संग्रह निर्माण के लिए कामना करता हूं। मेरा मानना ​​है कि डबल ब्रेस सिंटैक्स बहुत पठनीय है।

सूचियों के घोषणात्मक निर्माण को प्राप्त करने का एक और तरीका विशेष रूप से उपयोग करना Arrays.asList(T ...)है:

List<String> aList = Arrays.asList("vanilla", "strawberry", "chocolate");

इस दृष्टिकोण की सीमा निश्चित रूप से है कि आप विशिष्ट प्रकार की सूची को उत्पन्न करने के लिए नियंत्रित नहीं कर सकते हैं।


1
Arrays.asList () वह है जो मैं सामान्य रूप से उपयोग करता हूं, लेकिन आप सही हैं, यह स्थिति मुख्य रूप से इकाई परीक्षणों में उत्पन्न होती है; वास्तविक कोड डीबी प्रश्नों, XML, आदि से सूचियों का निर्माण करेगा।
जिम फेरेंस

7
हालांकि, सूची से सावधान रहें: लौटी हुई सूची तत्वों को जोड़ने या हटाने का समर्थन नहीं करती है। जब भी मैं asList का उपयोग करता हूं, मैं परिणामी सूची को एक कंस्ट्रक्टर में पास करता हूं जैसे new ArrayList<String>(Arrays.asList("vanilla", "strawberry", "chocolate"))कि इस समस्या को प्राप्त करना।
माइकल मायर्स

7

आम तौर पर इसके बारे में विशेष रूप से अक्षम कुछ भी नहीं है। यह आम तौर पर जेवीएम के लिए कोई फर्क नहीं पड़ता है कि आपने एक उपवर्ग बना दिया है और इसमें एक कंस्ट्रक्टर जोड़ा है - यह एक वस्तु-उन्मुख भाषा में एक सामान्य, रोजमर्रा की चीज है। मैं काफी वंचित मामलों के बारे में सोच सकता हूं, जहां आप ऐसा करके एक अक्षमता पैदा कर सकते हैं (जैसे आपके पास एक बार-बार विधि है जो इस उपवर्ग के कारण विभिन्न वर्गों के मिश्रण को समाप्त करती है, जबकि साधारण वर्ग में उत्तीर्ण होने वाला अनुमान पूरी तरह से अनुमानित होगा। - बाद के मामले में, जेआईटी कंपाइलर ऐसे अनुकूलन कर सकता है जो पहले संभव नहीं हैं)। लेकिन वास्तव में, मुझे लगता है कि जिन मामलों में यह बात होगी, वे बहुत ही विवादित हैं।

मैं इस मुद्दे को देखने के दृष्टिकोण से अधिक देखूंगा कि क्या आप बहुत सारी अनाम कक्षाओं के साथ "अव्यवस्था की बातें" करना चाहते हैं। एक मोटे गाइड के रूप में, ईवेंट हैंडलर के लिए अनाम कक्षाओं से अधिक नहीं, आपके द्वारा उपयोग किए जाने वाले मुहावरे का उपयोग करने पर विचार करें।

(2) में, आप किसी ऑब्जेक्ट के निर्माता के अंदर हैं, इसलिए "यह" उस ऑब्जेक्ट को संदर्भित करता है जिसका आप निर्माण कर रहे हैं। यह किसी भी अन्य निर्माता से अलग नहीं है।

(3) के रूप में, जो वास्तव में आपके कोड को बनाए रखने पर निर्भर करता है, मुझे लगता है। यदि आप इसे पहले से नहीं जानते हैं, तो एक बेंचमार्क जो मैं उपयोग करने का सुझाव दूंगा "क्या आप इसे JKK के स्रोत कोड में देखते हैं?" (इस मामले में, मुझे कई अनाम इनिशियलाइज़र को देखकर याद नहीं है, और निश्चित रूप से उन मामलों में नहीं है जहाँ यह अनाम वर्ग की एकमात्र सामग्री है)। अधिकांश मध्यम आकार की परियोजनाओं में, मैं तर्क देता हूं कि आप वास्तव में अपने प्रोग्रामर को किसी बिंदु या अन्य स्थान पर जेडीके स्रोत को समझने की आवश्यकता होगी, इसलिए वहां इस्तेमाल किया गया कोई भी वाक्यविन्यास या मुहावरा "निष्पक्ष खेल" है। इसके अलावा, मैं कहूंगा कि अगर आप कोड को बनाए रखने का नियंत्रण रखते हैं, तो लोग उस वाक्यविन्यास पर प्रशिक्षण दें, अन्यथा टिप्पणी करें या बचें।


5

डबल-ब्रेस इनिशियलाइज़ेशन एक अनावश्यक हैक है जो मेमोरी लीक और अन्य मुद्दों को पेश कर सकता है

इस "ट्रिक" का उपयोग करने का कोई वैध कारण नहीं है। अमरूद अच्छा स्थिर संग्रह प्रदान करता है जिसमें स्थिर कारखाने और बिल्डर दोनों शामिल हैं, आपको अपने संग्रह को आबाद करने की अनुमति देता है जहां यह एक साफ, पठनीय और सुरक्षित सिंटैक्स में घोषित किया जाता है ।

प्रश्न में उदाहरण बनता है:

Set<String> flavors = ImmutableSet.of(
    "vanilla", "strawberry", "chocolate", "butter pecan");

न केवल यह छोटा और पढ़ने में आसान है, लेकिन यह अन्य उत्तरों में वर्णित डबल-लट पैटर्न के साथ कई मुद्दों से बचा जाता है । निश्चित रूप से, यह एक सीधे-निर्मित के समान प्रदर्शन करता है HashMap, लेकिन यह खतरनाक और त्रुटि-प्रवण है, और बेहतर विकल्प हैं।

किसी भी समय आप अपने आप को डबल-ब्रेस्ड इनिशियलाइज़ेशन पर विचार करते हुए पाते हैं कि आपको अपने एपीआई की पुन: जांच करनी चाहिए या सिंटैक्टिक ट्रिक्स का लाभ लेने के बजाय समस्या का ठीक से समाधान करने के लिए नए लोगों से परिचय कराना चाहिए ।

त्रुटि-प्रवण अब इस विरोधी पैटर्न को चिह्नित करता है


-1। कुछ मान्य बिंदुओं के बावजूद, यह उत्तर "अनावश्यक अनाम वर्ग पैदा करने से कैसे बचें? एक फ्रेमवर्क का उपयोग करें, और भी अधिक वर्गों के साथ!"
Agent_L

1
मैं कहूंगा कि यह "काम के लिए सही उपकरण का उपयोग करने के लिए उबलता है, बजाय एक हैक के जो आपके एप्लिकेशन को क्रैश कर सकता है"। अमरूद अनुप्रयोगों के लिए एक बहुत ही सामान्य पुस्तकालय है (यदि आप इसका उपयोग नहीं कर रहे हैं तो आप निश्चित रूप से याद कर रहे हैं)
dimo414

और वास्तव में एक डबल ब्रेस इनिशियलाइज़ेशन कैसे एक मीरा रिसाव का कारण होगा?
एंजेल ओ'स्फीयर

@ एंजेलो स्फीयर डीबीआई एक आंतरिक वर्ग बनाने का एक शानदार तरीका है , और इसलिए इसके संलग्न वर्ग (जब तक कि कभी भी staticसंदर्भों में उपयोग नहीं किया गया है) के लिए एक अंतर्निहित संदर्भ बरकरार रखता है । मेरे प्रश्न के निचले भाग में त्रुटि-प्रवण लिंक आगे इस पर चर्चा करता है।
dimo414

मैं कहूंगा कि यह स्वाद का मामला है। और वहाँ वास्तव में इसके बारे में अप्रिय नहीं है।
एंजेल ओ 'स्फीयर

4

मैं इस पर शोध कर रहा था और मान्य उत्तर द्वारा प्रदान की गई तुलना में अधिक गहराई से परीक्षण करने का निर्णय लिया।

यहाँ कोड है: https://gist.github.com/4368924

और यह मेरा निष्कर्ष है

मुझे यह जानकर आश्चर्य हुआ कि अधिकांश परीक्षण में आंतरिक दीक्षा वास्तव में तेज थी (कुछ मामलों में लगभग दोगुनी)। जब बड़ी संख्या में काम करते हैं तो लाभ फीका लगता है।

दिलचस्प बात यह है कि, लूप पर 3 ऑब्जेक्ट्स बनाने वाला केस खो देता है, अन्य मामलों की तुलना में यह जल्द ही लाभान्वित होता है। मुझे यकीन नहीं है कि ऐसा क्यों हो रहा है और किसी निष्कर्ष पर पहुंचने के लिए और परीक्षण किए जाने चाहिए। ठोस कार्यान्वयन बनाने से वर्ग परिभाषा को फिर से लोड होने से बचने में मदद मिल सकती है (यदि ऐसा हो रहा है)

हालांकि, यह स्पष्ट है कि बहुत अधिक संख्या में यह नहीं देखा गया कि ज्यादातर मामलों में बड़ी संख्या के साथ एकल आइटम निर्माण के लिए।

एक सेट वापस तथ्य यह होगा कि प्रत्येक डबल ब्रेस दीक्षा एक नई क्लास फाइल बनाता है जो हमारे एप्लिकेशन के आकार में एक संपूर्ण डिस्क ब्लॉक जोड़ता है (या संकुचित होने पर 1k)। एक छोटा पदचिह्न, लेकिन अगर इसे कई जगहों पर उपयोग किया जाता है तो संभावित रूप से इसका प्रभाव पड़ सकता है। इस 1000 बार का उपयोग करें और आप संभावित रूप से आप के लिए एक पूरे MiB जोड़ रहे हैं applicaiton, जो एक एम्बेडेड वातावरण पर संबंधित हो सकता है।

मेरा निष्कर्ष? जब तक इसका दुरुपयोग नहीं होता है तब तक इसका उपयोग करना ठीक हो सकता है।

आप क्या सोचते हैं मुझे बताओ :)


2
यह एक वैध परीक्षण नहीं है। कोड उन वस्तुओं का उपयोग किए बिना बनाता है जो ऑप्टिमाइज़र को पूरी आवृत्ति निर्माण को खत्म करने की अनुमति देता है। केवल शेष दुष्परिणाम यादृच्छिक संख्या अनुक्रम की उन्नति है जिसका ओवरहेड वैसे भी इन परीक्षणों में कुछ और आगे निकलता है।
होल्गर

3

मैं दूसरे नट का उत्तर देता हूं, सिवाय इसके कि मैं बनाने के बजाय एक लूप का उपयोग करूंगा और तुरंत asList से निहित सूची को हटा दूंगा (तत्व:

static public Set<T> setOf(T ... elements) {
    Set set=new HashSet<T>(elements.size());
    for(T elm: elements) { set.add(elm); }
    return set;
    }

1
क्यों? नई वस्तु को एडन स्पेस में बनाया जाएगा, और इसलिए केवल दो या तीन पॉइंटर जोड़ को तुरंत करने की आवश्यकता है। जेवीएम यह नोटिस कर सकता है कि यह विधि के दायरे से बाहर नहीं निकलता है और इसलिए इसे स्टैक पर आवंटित करें।
नेट

हाँ, यह उस कोड की तुलना में अधिक कुशल होने की संभावना है (हालांकि आप HashSetकिसी सुझाई गई क्षमता - लोड लोड फैक्टर को याद करके इसे बेहतर बना सकते हैं )।
टॉम हॉकिन -

ठीक है, हाशसेट निर्माता को वैसे भी पुनरावृत्ति करना है, इसलिए यह कम कुशल नहीं है। पुन: उपयोग के लिए बनाया गया लाइब्रेरी कोड हमेशा सबसे अच्छा संभव होने का प्रयास करना चाहिए ।
लॉरेंस डॉल

3

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


3

मारियो Gleichman का वर्णन है कि स्केल सूची शाब्दिकों का अनुकरण करने के लिए जावा 1.5 सामान्य कार्यों का उपयोग कैसे करें, हालांकि दुख की बात है कि आप अपरिवर्तनीय सूचियों के साथ हवा देते हैं ।

वह इस वर्ग को परिभाषित करता है:

package literal;

public class collection {
    public static <T> List<T> List(T...elems){
        return Arrays.asList( elems );
    }
}

और इस प्रकार इसका उपयोग करता है:

import static literal.collection.List;
import static system.io.*;

public class CollectionDemo {
    public void demoList(){
        List<String> slist = List( "a", "b", "c" );
        List<Integer> iList = List( 1, 2, 3 );
        for( String elem : List( "a", "java", "list" ) )
            System.out.println( elem );
    }
}

Google संग्रह, अब अमरूद का हिस्सा सूची निर्माण के लिए एक समान विचार का समर्थन करता है। में इस साक्षात्कार , जारेड लेवी का कहना है:

[...] सबसे अधिक उपयोग की जाने वाली विशेषताएँ, जो मेरे द्वारा लिखे गए लगभग हर जावा वर्ग में दिखाई देती हैं, वे स्थिर विधियाँ हैं जो आपके जावा कोड में दोहराए जाने वाले कीस्ट्रोक्स की संख्या को कम करती हैं। यह इतना सुविधाजनक है कि निम्नलिखित जैसे कमांड दर्ज करने में सक्षम है:

Map<OneClassWithALongName, AnotherClassWithALongName> = Maps.newHashMap();

List<String> animals = Lists.immutableList("cat", "dog", "horse");

7/10/2014: यदि केवल यह अजगर के रूप में सरल हो सकता है:

animals = ['cat', 'dog', 'horse']

2/21/2020: जावा 11 में अब आप कह सकते हैं:

animals = List.of(“cat”, “dog”, “horse”)


2
  1. यह add()प्रत्येक सदस्य के लिए कॉल करेगा । यदि आप हैश सेट में आइटम डालने के लिए अधिक कुशल तरीका पा सकते हैं, तो इसका उपयोग करें। ध्यान दें कि यदि आप उस बारे में संवेदनशील हैं, तो आंतरिक वर्ग कचरा उत्पन्न करेगा।

  2. यह मुझे ऐसा लगता है जैसे संदर्भ वह वस्तु है जिसे लौटाया गया है new, जो कि है HashSet

  3. यदि आपको पूछने की आवश्यकता है ... अधिक संभावना है: आपके बाद आने वाले लोग यह जानते हैं या नहीं? क्या इसे समझना और समझाना आसान है? यदि आप दोनों को "हां" जवाब दे सकते हैं, तो इसका उपयोग करने के लिए स्वतंत्र महसूस करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.