2012-03-01 17 views
15

के रूप में अमरूद अपरिवर्तनीय संग्रह का उपयोग मैं यह निर्धारित करने की कोशिश कर रहा हूं कि एक अपरिवर्तनीय सूची के लिए सर्वोत्तम प्रथा क्या होगी।विधि पैरामीटर और/या वापसी प्रकार

पूर्व:

public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){ 
    //.. do some work 
    ImmutableList<Foo> fooOther = // something generated during the code 
    return fooOther; 
} 

public Collection<Foo> getFooTwo(List<Foo> fooInput){ 
    //.. do some work 
    List<Foo> fooOther = // something generated during the code 
    return ImmutableList.copyOf(fooOther); 
} 

public void doSomethingOne(){ 
    ImmutableCollection<Foo> myFoo = getFooOne(myList); 
    ... 
    someOtherMethod(myFoo); 
} 

public void doSomethingTwo(){ 
    Collection<Foo> myFoo = getFooOne(myList); 
    ... 
    someOtherMethod(myFoo); 
} 

मेरे सवाल: नीचे एक साधारण उदाहरण में मदद मिलेगी मेरे सवालों की दूरी पर है

  1. कौन सा सबसे अधिक उपयुक्त एक आवेदन में उपयोग करने के लिए बनाता है? [doSomethingOne और getFooOne] या [doSomethingTwo और fooTwo]? दूसरे शब्दों में यदि आप जानते हैं कि आप ImmutableCollections का उपयोग कर रहे हैं, तो क्या यह आगे और आगे कास्टिंग रखने और copyOf() करने के लिए समझ में आता है, या बस हर जगह अपरिवर्तनीय उपयोग करें?

  2. ये उदाहरण सार्वजनिक विधियां हैं जो दर्शा सकती हैं कि अन्य लोग उनका उपयोग करते हैं। यदि विधियां निजी थीं और आंतरिक रूप से उपयोग की जाती हैं तो क्या इनमें से कोई भी जवाब बदल जाएगा?

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

+4

आप यहां क्या करने की कोशिश कर रहे हैं? क्या आप इन सूचियों को संशोधित करने से आंतरिक और बाहरी कोड की रक्षा करने की कोशिश कर रहे हैं? क्या आप एक कदम वापस ले सकते हैं और कुछ पृष्ठभूमि प्रदान कर सकते हैं? धन्यवाद। – Gray

+2

@ ग्रे: * "आप यहां क्या हासिल करने की कोशिश कर रहे हैं? क्या आप इन सूचियों को संशोधित करने से आंतरिक और बाहरी कोड की रक्षा करने की कोशिश कर रहे हैं?" * [एसआईसी] ... ओपी कुछ प्रसंस्करण के बाद एक अपरिवर्तनीय सूची लेना और वापस लेना चाहता है, एक और अपरिवर्तनीय सूची। * "संशोधन से कोड की रक्षा" * की तुलना में अपर्याप्तता के लिए * अधिक * अधिक है। अपरिवर्तनीयता के लाभ इतने विशाल हैं (अंतर्निहित थ्रेड-सुरक्षा, आसान समांतरता, आसान कैशिंग, राज्य को पुन: उत्पन्न करने में आसान इत्यादि) कि हाल ही की कई भाषाओं (क्लोजर, एफ #, ...) में अपरिवर्तनीयता मुक्त होती है। अपरिवर्तनीयता का उपयोग करने के लिए किसी की इच्छा को औचित्य देने के लिए * शून्य * आवश्यकता है;) – TacticalCoder

+0

उह, निश्चित @TacticalCoder। मैं बस बेहतर समझना चाहता था कि लक्ष्य क्या था। यह सवाल मेरे लिए बहुत सटीक लगता है। यदि उसने यहां समझाया कि क्या पूरा करने की कोशिश कर रहा था, तो मुझे लगता है कि एक बेहतर जवाब संभव होगा। – Gray

उत्तर

18

सामान्यतः, अपने घोषित रिटर्न प्रकार में एक विशिष्ट कार्यान्वयन के लिए प्रतिबद्ध नहीं है, लेकिन हम अपरिवर्तनीय प्रकारों को अपवाद के रूप में सोचते हैं। कुछ कारणों से Immutable* की वापसी प्रकार की घोषणा करने के हैं:

  • वे दस्तावेज़ है कि आप एक स्नैपशॉट, नहीं एक जीवित दृश्य वापस लौट रहे हैं।
  • वे दस्तावेज करते हैं कि कॉलर परिणाम को उत्परिवर्तित नहीं कर सकता है।
  • वे दस्तावेज करते हैं कि सम्मिलन आदेश संरक्षित है (जो आपके उपयोग मामले में महत्वपूर्ण हो सकता है या नहीं)।
  • वे दस्तावेज करते हैं कि संग्रह में null नहीं होगा।
  • कोई भी asList() या reverse() विधि चाहेगा।
  • यदि आप Immutable* फ़ील्ड को असाइन करना चाहते हैं तो आप किसी को copyOf() कॉल से बचा सकते हैं। (लेकिन ध्यान दें कि, यदि वह copyOf() शामिल करता है, यह सबसे अपरिवर्तनीय आदानों के लिए शॉर्ट सर्किट होगा, भले ही आप वापसी प्रकार की घोषणा नहीं है।)

असल में, मैं सिर्फ https://github.com/google/guava/wiki/TenThingsAboutImmutableCollections से cribbing कर रहा हूँ, जो आप पूरी तरह से जांचना चाह सकते हैं।

/** 
* Returns an <b>immutable copy</b> of input list. 
*/ 
public ImmutableList<Foo> immutableCopyOfFoo(List<Foo> input){ 
    return ImmutableList.copyOf(input); 
} 

क्यों:

+0

लिंक के लिए धन्यवाद! – user973479

0

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

यदि आप समवर्ती संशोधन के बारे में चिंतित हैं, तो आपको सार्वजनिक तरीकों पर प्रदान की गई सूचियों की रक्षात्मक प्रतियां बनाना चाहिए, लेकिन निजी विधि तर्कों पर ImmutableCollection निर्दिष्ट करना ठीक है।

+2

"गुवा के अपरिवर्तनीय ... कक्षाओं पर कोई अतिरिक्त विधियां नहीं हैं इसलिए आप किसी भी संकलन-समय की सुरक्षा प्राप्त नहीं कर रहे हैं" - माना जाता है कि * FindBugs * एक बग की रिपोर्ट करता है जब आप एक प्रकार के संदर्भ में एक उत्परिवर्तनीय विधि को कॉल करते हैं 'अपरिवर्तनीय ... ', तो आप थोड़ा अतिरिक्त सुरक्षा प्राप्त कर सकते हैं। इसका कारण यह है कि यह देख सकता है कि वे विधियां सिर्फ अपवाद फेंकती हैं (माना जाता है कि मेरे पास कोई व्यक्तिगत अनुभव नहीं है)। –

+0

ओओ मुझे नहीं पता था कि ... – artbristol

1
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){ 
    ImmutableList<Foo> fooOther= fooInput; 
    return ImmutableList.copyOf(fooOther); 
} 

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

public Collection<Foo> getFooTwo(List<Foo> fooInput){ 
    ImmutableList<Foo> fooOther= ImmutableList.copyOf(fooInput); 
    return ImmutableList.copyOf(fooOther); 
} 

??? यह दो बार क्यों ??? यह ठीक है:

public Collection<Foo> getFooTwo(List<Foo> fooInput){ 
    return ImmutableList.copyOf(fooInput); 
} 

ImmutableList.copyOf(Collection) बहुत चालाक ImmutableList असंशोधित लौट सकते हैं और सब कुछ के लिए एक नया ImmutableList तैयार करना है।

+0

क्षमा करें कि एक टाइपो था। मैंने इसे मूल पोस्ट में तय किया। हालांकि अगर कोई getFooTwo() से सामान्य संग्रह को वापस करने की अपेक्षा करता है और फिर संग्रह में कुछ जोड़ने का प्रयास करता है तो अपवाद फेंक दिया जाएगा। तो, क्या यह एक अपरिवर्तनीय चयन को स्पष्ट रूप से वापस करने के लिए और अधिक समझ में आता है? – user973479

+0

@ user973479 या तो स्पष्ट रूप से अपरिवर्तनीय (सूची | संग्रह) लौटाएं या स्पष्ट रूप से विधि के javadoc में अपरिवर्तनीयता दस्तावेज करें। –

2

अगर मैं अपने इरादों समझा, हो सकता है-परिवर्तनशील-सूची का एक अपरिवर्तनीय प्रतिलिपि बनाने के लिए getFooXxx को डिजाइन करने का उचित तरीके से कुछ इस तरह है?

  • ImmutableList.copyOf()does it's magic जब दी गई सूची में अपरिवर्तनीय है,
  • विधि हस्ताक्षर स्पष्ट रूप से कहते हैं कि वह क्या करता,
  • विधि रिटर्न ImmutableList जो है, वास्तव में, एक ImmutableCollection लेकिन क्यों आप के बारे में जानकारी को छिपाने के लिए चाहते हैं ImmutableList उपयोगकर्ता से? वह चाहता है, तो वह Iterable foo = immutableCopyOfFoo(mutableFoo); बजाय लिखेंगे, लेकिन 99% वह एक ImmtableList,
  • इस्तेमाल करेंगे लौटने एक ImmutableListएक वादा बनाता है - "मैं अडिग हूँ, और मैं सब कुछ उड़ा अगर आप को बदलने की कोशिश करेंगे मुझे! "
  • और अंतिम लेकिन कम से कम नहीं - प्रस्तावित विधि अनावश्यक आंतरिक उपयोग में है; सिर्फ इतना है कि यानी पता करने के लिए जब List<Foo> inputnull रों होता है का उपयोग

    someOtherMethod(ImmutableList.copyOf(foo)); 
    
    सीधे अपने कोड में

    ...


आप @ChrisPovirk's answer की जाँच करनी चाहिए (और लिंक है कि जवाब में विकि के लिए), तो आपको यदि आप एक अपरिवर्तनीय प्रतिलिपि बनाने का प्रयास करते हैं तो रनटाइम पर बुरा एनपीई मिलेगा ...


संपादित जवाब टिप्पणी # 1:

Collection अनुबंध List के एक तुलना में कम सख्त है, यानी संग्रह तत्वों के किसी भी क्रम की गारंटी नहीं देता है ("कुछ आदेश दिए जाते हैं और अन्य अनियंत्रित होते हैं") जबकि सूची करता है ("एक आदेशित संग्रह (अनुक्रम के रूप में भी जाना जाता है)")।

यदि कोई इनपुट सूची सूचीबद्ध करता है तो यह सुझाव देता है कि आदेश महत्वपूर्ण है और इसलिए उत्पादन को इसकी गारंटी देनी चाहिए। कल्पना कीजिए कि:

public ImmutableCollection<Foo> immutableCopyOfFoo(List<Foo> input){ 
    return ImmutableSortedSet.copyOf(input, someFancyComparator); 
} 

यह सही गंध नहीं करता है। यदि आपको आदेश की परवाह नहीं है तो शायद विधि हस्ताक्षर immutableCopyOfFoo(Collection<Foo> input) होना चाहिए? लेकिन यह ठोस उपयोग मामले पर निर्भर करता है।

+0

आपकी प्रतिक्रिया के लिए धन्यवाद। मुझे यकीन नहीं है कि मैं एक अपरिवर्तनीय चयन का उपयोग क्यों नहीं कर सकता अगर मुझे पता है कि कोई विशिष्ट इम्यूटेबललिस्ट कार्यक्षमता की आवश्यकता नहीं है? मुझे पता है कि प्रस्तावित तरीके अनावश्यक हैं लेकिन मैं सिर्फ एक साधारण उदाहरण को एक साथ रखना चाहता था। वास्तविक तरीके काम करेंगे और इनपुट में दिए गए की तुलना में शायद एक अलग संग्रह वापस कर देंगे। – user973479

+0

@ user973479: मैंने ऊपर दिए गए मेरे उत्तर में जवाब दिया। – Xaerxess

+0

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

1

मेरे सामान्य दृष्टिकोण है:

  • मापदंडों

  • अगर प्रदर्शन/स्मृति उपयोग/धागे की सुरक्षा महत्वपूर्ण है (ताकि इंटरफेस ग्राहकों के लिए उपयोग करने के लिए आसान है) के लिए सूची स्वीकार करते हैं, नकल प्रदान की गई सूची की सामग्री को डेटा संरचना में उपयोग किया जाता है जिसे आपकी कक्षा

  • एक अपरिवर्तनीय लौटाते समय, अपरिवर्तनीय सूची वापसी प्रकार होना चाहिए (क्योंकि यह कॉलर को इस बारे में अधिक जानकारी देता है कि कैसे यह मान का उपयोग कर सकते)

  • जब सूची का एक परिवर्तनशील कार्यान्वयन लौटने सूची वापसी प्रकार, किया जाना चाहिए जब तक वापसी प्रकार के बारे में कुछ और महत्वपूर्ण (धागे की सुरक्षा है, एक बुरा * उदाहरण के रूप में)

* यह एक बुरा उदाहरण है क्योंकि यदि आपके वापसी मूल्यों को थ्रेड-सुरक्षित होना आवश्यक है, तो शायद इसका मतलब है कि आपके कोड में कुछ और गलत है।

किसी भी अपरिवर्तनीय संग्रह प्रकारों के साथ सूची/अपरिवर्तनीय सूची बदलें।

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