Java 8 में अपरिवर्तनीय संग्रह क्यों नहीं हैं?


130

जावा टीम ने जावा 8. में कार्यात्मक प्रोग्रामिंग में बाधाओं को दूर करने का एक टन का काम किया है। विशेष रूप से, java.util कलेक्शंस में बदलाव बहुत तेजी से सुव्यवस्थित परिचालनों में परिवर्तन का पीछा करने का एक बड़ा काम करते हैं। यह देखते हुए कि संग्रह पर प्रथम श्रेणी के कार्यों और कार्यात्मक तरीकों को जोड़कर उन्होंने कितना अच्छा काम किया है, क्यों वे अपरिवर्तनीय संग्रह या यहां तक ​​कि अपरिवर्तनीय संग्रह इंटरफेस प्रदान करने में पूरी तरह से विफल रहे हैं?

किसी भी मौजूदा कोड को बदलने के बिना, जावा टीम किसी भी समय अपरिवर्तनीय इंटरफेस को जोड़ सकती है, जो कि परिवर्तनशील लोगों के समान हैं, "सेट" विधियों को माइनस करते हैं और मौजूदा इंटरफेस को इस तरह से बढ़ाते हैं:

                  ImmutableIterable
     ____________/       |
    /                    |
Iterable        ImmutableCollection
   |    _______/    /          \   \___________
   |   /           /            \              \
 Collection  ImmutableList  ImmutableSet  ImmutableMap  ...
    \  \  \_________|______________|__________   |
     \  \___________|____________  |          \  |
      \___________  |            \ |           \ |
                  List            Set           Map ...

निश्चित रूप से, सूची .add () और Map.put () जैसे ऑपरेशन वर्तमान में दिए गए कुंजी के लिए एक बूलियन या पिछला मान लौटाते हैं, यह इंगित करने के लिए कि ऑपरेशन सफल हुआ या विफल। अपरिवर्तनीय संग्रह को कारखानों के रूप में इस तरह के तरीकों का इलाज करना होगा और जोड़े गए तत्व के साथ एक नया संग्रह लौटना होगा - जो वर्तमान हस्ताक्षर के साथ असंगत है। लेकिन ImmutableList.append () या .addAt () और ImmutableMap.putEntry () जैसे एक अलग विधि नाम का उपयोग करके काम किया जा सकता है। परिणामस्वरूप संग्रहणीयता अपरिवर्तनीय संग्रह के साथ काम करने के लाभों से अधिक होगी, और प्रकार प्रणाली गलत पद्धति को कॉल करने की त्रुटियों को रोक देगी। समय के साथ, पुराने तरीकों को हटा दिया जा सकता था।

अपरिवर्तनीय संग्रह की जीत:

  • सरलता - कोड के बारे में तर्क सरल है जब अंतर्निहित डेटा नहीं बदलता है।
  • प्रलेखन - यदि कोई विधि अपरिवर्तनीय संग्रह इंटरफ़ेस लेता है, तो आप जानते हैं कि यह उस संग्रह को संशोधित करने वाला नहीं है। यदि कोई विधि अपरिवर्तनीय संग्रह लौटाती है, तो आप जानते हैं कि आप इसे संशोधित नहीं कर सकते।
  • कंजेंसी - अपरिवर्तनीय संग्रह को थ्रेड्स में सुरक्षित रूप से साझा किया जा सकता है।

जैसा कि किसी ने उन भाषाओं का स्वाद चखा है जो अपरिवर्तनीयता का अनुमान लगाते हैं, जंगली जंगली उत्परिवर्ती उत्परिवर्तन पर वापस जाना बहुत कठिन है। क्लोजर के संग्रह (सीक्वेंस एब्स्ट्रक्शन) में पहले से ही सब कुछ है जो जावा 8 संग्रह प्रदान करता है, प्लस अपरिवर्तनीयता (हालांकि स्ट्रीम के बजाय लिंक किए गए सूचियों के कारण अतिरिक्त मेमोरी और समय का उपयोग कर सकता है)। स्काला के पास संचालन के पूरे सेट के साथ परस्पर और अपरिवर्तनीय दोनों संग्रह हैं, और हालांकि वे संचालन उत्सुक हैं, कॉलिंग .iterator एक आलसी दृश्य देता है (और आलसी के अन्य तरीके हैं जो उनका मूल्यांकन कर रहे हैं)। मैं यह नहीं देखता कि जावा अपरिवर्तनीय संग्रह के बिना प्रतिस्पर्धा कैसे जारी रख सकता है।

क्या कोई मुझे इतिहास या इस बारे में चर्चा करने के लिए कह सकता है? निश्चित रूप से यह कहीं न कहीं सार्वजनिक है।


9
इससे संबंधित - आयेंडे ने हाल ही में बेंचमार्क के साथ सी # में संग्रह और अपरिवर्तनीय संग्रह के बारे में ब्लॉग किया। ayende.com/blog/tags/performance - tl; dr - अपरिवर्तनीयता धीमी है
ओडेड

20
आपकी पदानुक्रम के साथ मैं आपको एक ImmutableList दे सकता हूं और फिर इसे आप पर तब बदल सकता हूं जब आपको यह उम्मीद नहीं होगी कि बहुत सारी चीजें टूट सकती हैं, जैसा कि आपके पास केवल constसंग्रह है
शाफ़्ट फ्रीक

18
@Oded Immutability धीमी है, लेकिन इसलिए लॉकिंग है। इसलिए एक इतिहास बनाए हुए है। सादगी / सुधार कई स्थितियों में गति के लायक है। छोटे संग्रह के साथ, गति एक मुद्दा नहीं है। आयेंडे का विश्लेषण इस धारणा पर आधारित है कि आपको इतिहास, लॉकिंग या सादगी की आवश्यकता नहीं है और आप एक बड़े डेटा सेट के साथ काम कर रहे हैं। कभी-कभी यह सच है, लेकिन यह एक-हमेशा-बेहतर चीज नहीं है। ट्रेड-ऑफ हैं।
ग्लेनपेटर्सन

5
@GlenPeterson क्या रक्षात्मक प्रतियां और के लिए Collections.unmodifiable*()कर रहे हैं। लेकिन जब वे नहीं हैं, तो उन्हें अपरिवर्तनीय न
मानें

13
एह? यदि आपका कार्य ImmutableListउस आरेख में होता है, तो लोग एक परिवर्तनशील में पारित कर सकते हैं List? नहीं, यह एलएसपी का बहुत बुरा उल्लंघन है।
तेलस्टिन

जवाबों:


113

क्योंकि अपरिवर्तनीय संग्रह को पूरी तरह से साझा करने की आवश्यकता होती है। अन्यथा, हर एक ऑपरेशन कहीं और पूरी सूची को ढेर में गिरा देता है। वे भाषाएँ जो हास्केल की तरह पूरी तरह अपरिवर्तनीय हैं, आक्रामक अनुकूलन और साझा किए बिना कचरे की आश्चर्यजनक मात्रा उत्पन्न करती हैं। संग्रह के बाद केवल <50 तत्वों के साथ प्रयोग करने योग्य है जो मानक पुस्तकालय में डालने लायक नहीं है।

इसके अलावा, अपरिवर्तनीय संग्रह में अक्सर उनके परस्पर समकक्षों की तुलना में मौलिक रूप से अलग कार्यान्वयन होते हैं। उदाहरण के लिए विचार करें ArrayList, एक कुशल अपरिवर्तनीय ArrayListएक सरणी बिल्कुल नहीं होगा! यह एक बड़े ब्रांचिंग कारक के साथ एक संतुलित पेड़ के साथ लागू किया जाना चाहिए, क्लोज़र 32 आईआईआरसी का उपयोग करता है। केवल एक कार्यात्मक अद्यतन जोड़कर परिवर्तनशील संग्रह को "अपरिवर्तनीय" बनाया जाना एक मेमोरी बग जितना ही एक प्रदर्शन बग है।

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

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


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

4
मैं आपके उत्तर को फिर से पढ़ता हूं और मुझे लगता है कि आप कह रहे हैं कि जावा में पारस्परिकता (जैसे जावा बीन्स) की एक मौलिक धारणा है और संग्रह सिर्फ हिमशैल के टिप हैं और उस टिप को उकेरना अंतर्निहित समस्या को हल नहीं करेगा। एक वैध बिंदु। मैं इस उत्तर को स्वीकार कर सकता हूं और स्कैला को अपना सकता हूं! :-)
ग्लेनपेटर्सन

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

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

4
jozefg, संरचनात्मक साझाकरण के साथ जेवीएम पर कुशल अपरिवर्तनीय संग्रह को लागू करना पूरी तरह से संभव है। स्काला और क्लॉजुर उनके मानक पुस्तकालय के हिस्से के रूप में हैं, दोनों कार्यान्वयन फिल बागवेल के एचएएमटी (हैश अर्रे मैप्ड ट्राइ) पर आधारित हैं। BALANCED पेड़ों के साथ अपरिवर्तनीय डेटा संरचनाओं को लागू करने के बारे में आपका कथन पूरी तरह से गलत है।
20

77

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

  • एक पठनीय संग्रह आधार वर्ग या इंटरफ़ेस प्रकार वादा करता है कि कोई आइटम पढ़ सकता है, और संग्रह को संशोधित करने का कोई प्रत्यक्ष साधन प्रदान नहीं करता है, लेकिन यह गारंटी नहीं देता है कि संदर्भ प्राप्त करने वाला कोड डाली नहीं जा सकता है या इसे इस तरह से हेरफेर कर सकता है जैसे संशोधन की अनुमति देने के लिए।

  • एक रीड-ओनली कलेक्शन इंटरफ़ेस में कोई नया सदस्य शामिल नहीं है, लेकिन इसे केवल एक वर्ग द्वारा लागू किया जाना चाहिए जो वादा करता है कि इस तरह से एक संदर्भ में हेरफेर करने का कोई तरीका नहीं है, जैसे कि संग्रह को म्यूट करना और न ही किसी चीज़ का संदर्भ प्राप्त करना। ऐसा कर सकता था। हालांकि, यह वादा नहीं करता है कि संग्रह को कुछ और द्वारा संशोधित नहीं किया जाएगा जिसमें आंतरिक लोगों का संदर्भ है। ध्यान दें कि केवल-पढ़ने वाला संग्रह इंटरफ़ेस, उत्परिवर्तनीय कक्षाओं द्वारा कार्यान्वयन को रोकने में सक्षम नहीं हो सकता है, लेकिन यह निर्दिष्ट कर सकता है कि कार्यान्वयन से प्राप्त कोई भी कार्यान्वयन, या वर्ग, जो म्यूटेशन को "नाजायज" कार्यान्वयन या कार्यान्वयन के व्युत्पन्न माना जाएगा। ।

  • एक अपरिवर्तनीय संग्रह वह है जो हमेशा उसी डेटा को धारण करेगा जब तक कि उसका कोई संदर्भ मौजूद न हो। एक अपरिवर्तनीय इंटरफ़ेस का कोई भी कार्यान्वयन जो किसी विशेष अनुरोध के जवाब में हमेशा एक ही डेटा को वापस नहीं करता है।

यह कभी-कभी दृढ़ता से जुड़े उत्परिवर्तनीय और अपरिवर्तनीय संग्रह प्रकारों के लिए उपयोगी होता है जो एक ही "पठनीय" प्रकार से लागू होते हैं या प्राप्त होते हैं, और पठनीय प्रकार को शामिल करने AsImmutableके लिए AsMutable, और AsNewMutableविधियाँ। ऐसा डिज़ाइन कोड की अनुमति दे सकता है जो कॉल करने के लिए संग्रह में डेटा को जारी रखना चाहता है AsImmutable; यदि संग्रह सुपाच्य है, तो यह विधि एक रक्षात्मक प्रतिलिपि बना देगी, लेकिन यदि यह पहले से ही अपरिवर्तनीय है तो प्रतिलिपि को छोड़ दें।


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

1
@ लॉरेंटबोरगल्ट-रॉय: सील और निहित अपरिवर्तनीय दोनों प्रकार के फायदे हैं। यदि कोई किसी गैरकानूनी व्युत्पन्न वर्ग को किसी के आक्रमणकारियों को तोड़ने की अनुमति नहीं देना चाहता है, तो सील किए गए प्रकार उसके खिलाफ सुरक्षा प्रदान कर सकते हैं, जबकि अंतर्निहित वर्ग कोई भी प्रस्ताव नहीं देते हैं। दूसरी ओर, यह कोड है कि डेटा इसे स्टोर करने के लिए रखती है के बारे में कुछ जानता है के लिए संभव हो सकता है बहुत अधिक दृढ़तापूर्वक एक प्रकार है कि इसके बारे में कुछ नहीं जानता की तुलना में। उदाहरण के लिए, एक ReadableIndexedIntSequence प्रकार पर विचार करें, जो intतरीकों के साथ getLength()और , का एक क्रम encapsulate करता है getItemAt(int)
सुपरकैट

1
@ लॉरेंटबोरगौल्ट-रॉय: ए को देखते हुए ReadableIndexedIntSequence, सभी मदों को एक सरणी में कॉपी करके एक सरणी-समर्थित अपरिवर्तनीय प्रकार का उदाहरण पेश किया जा सकता है, लेकिन मान लीजिए कि एक विशेष कार्यान्वयन केवल 16777216 लंबाई और ((long)index*index)>>24प्रत्येक आइटम के लिए वापस आ गया । यह पूर्णांकों का एक वैध अपरिवर्तनीय अनुक्रम होगा, लेकिन इसे एक सरणी में कॉपी करना समय और स्मृति का एक बड़ा बेकार होगा।
सुपरकैट

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

1
@ लॉरेंटबोरगौल्ट-रॉय: मूल प्रश्न यह है कि क्या कोई विश्वास करता है कि लोग टूटी हुई कार्यान्वयन या व्युत्पन्न वर्ग का उत्पादन नहीं करेंगे। यदि कोई करता है, और यदि इंटरफेस / बेस कक्षाएं asMutable / asImmutable तरीके प्रदान करते हैं, तो परिमाण के कई आदेशों द्वारा प्रदर्शन में सुधार करना संभव हो सकता है [ asImmutableउदाहरण के लिए उपरोक्त परिभाषित अनुक्रम बनाम निर्माण की लागत के उदाहरण पर कॉल करने की लागत की तुलना करें] एक अपरिवर्तनीय सरणी-समर्थित प्रतिलिपि]। मैं कहता हूं कि इस तरह के उद्देश्यों के लिए परिभाषित इंटरफेस होने से शायद तदर्थ दृष्टिकोण का उपयोग करने की कोशिश करना बेहतर है; IMHO, सबसे बड़ा कारण ...
16

15

जावा कलेक्शंस फ्रेमवर्क java.util.Collections वर्ग में छह स्थिर तरीकों के माध्यम से एक संग्रह का केवल-पढ़ने के लिए संस्करण बनाने की क्षमता प्रदान करता है :

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

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


4
अपरिवर्तनीय संग्रहों के डिजाइन में बहुत वृद्धि हुई होती यदि रैपरों में यह संकेत शामिल होता कि क्या लिपटे हुए सामान पहले से ही अपरिवर्तनीय हैं, और immutableListआदि कारखाने के तरीके थे जो एक पारित-प्रति की प्रति के आसपास एक रीड-ओनली रैपर लौटा देते थे । सूची जब तक पारित सूची पहले से अपरिवर्तनीय नहीं थी । उपयोगकर्ता-परिभाषित प्रकारों को बनाना आसान होगा, लेकिन एक समस्या के लिए: joesCollections.immutableListविधि के लिए यह पहचानने का कोई तरीका नहीं होगा कि इसे उस ऑब्जेक्ट को कॉपी करने की आवश्यकता नहीं है जो उसके द्वारा लौटाया गया है fredsCollections.immutableList
सुपरकाट

8

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

एक प्रतिशत जावा प्रोग्रामर वर्ग unmodifiableCollection()के तरीकों के परिवार के अस्तित्व के बारे में जानते हैं Collections, लेकिन उनमें से भी, कई लोग इसके साथ परेशान नहीं करते हैं।

और मैं उन्हें दोष नहीं दे सकता: एक इंटरफ़ेस जो पढ़ने-लिखने का दिखावा करता है, लेकिन फेंक देगा UnsupportedOperationExceptionयदि आप इसके किसी भी 'लिखने' के तरीके को लागू करने की गलती करते हैं, तो यह बहुत बुरी बात है!

अब, ऐसा इंटरफ़ेस, Collectionजो अनुपलब्ध होगा add(), remove()और clear()विधियाँ "ImmutableCollection" इंटरफ़ेस नहीं होगी; यह एक "UnmodifiableCollection" इंटरफ़ेस होगा। तथ्य की बात के रूप में, एक "ImmutableCollection" इंटरफ़ेस कभी नहीं हो सकता है, क्योंकि अपरिवर्तनशीलता एक कार्यान्वयन की एक प्रकृति है, न कि एक इंटरफ़ेस की विशेषता। मुझे पता है, यह बहुत स्पष्ट नहीं है; मुझे समझाने दो।

मान लीजिए कि कोई व्यक्ति आपको केवल पढ़ने के लिए संग्रह इंटरफ़ेस देता है; क्या इसे किसी अन्य धागे से पास करना सुरक्षित है? यदि आप सुनिश्चित करते हैं कि यह वास्तव में अपरिवर्तनीय संग्रह का प्रतिनिधित्व करता है, तो इसका उत्तर "हां" होगा; दुर्भाग्य से, चूंकि यह एक इंटरफ़ेस है, आप नहीं जानते कि इसे कैसे लागू किया जाता है, इसलिए उत्तर को एक नहीं होना चाहिए : आप सभी जानते हैं, यह एक संग्रह के लिए एक अपरिवर्तनीय (आप के लिए) दृश्य हो सकता है जो वास्तव में परिवर्तनशील है, (जैसे आपको क्या मिलता है Collections.unmodifiableCollection()), इसलिए इसे पढ़ने की कोशिश करते समय एक और धागा संशोधित होने के कारण यह भ्रष्ट डेटा को पढ़ सकता है।

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

अपरिवर्तनीय संग्रह रखने के लिए, उन्हें वर्ग बनाना होगा , इंटरफेस नहीं!

इन अपरिवर्तनीय संग्रह कक्षाओं को अंतिम रूप देना होगा, ताकि जब आपको इस तरह के संग्रह का संदर्भ दिया जाए तो आप निश्चित रूप से जान सकें कि यह एक अपरिवर्तनीय संग्रह के रूप में व्यवहार करेगा, चाहे आप या कोई भी व्यक्ति जिसके पास इसका संदर्भ हो, वह हो सकता है इसके साथ करो।

तो, जावा, (या किसी अन्य घोषणात्मक अनिवार्य भाषा) में संग्रह का एक पूरा सेट रखने के लिए, हमें निम्नलिखित की आवश्यकता होगी:

  1. अनम्य संग्रह इंटरफेस का एक सेट ।

  2. परिवर्तनशील संग्रह इंटरफेस का एक सेट , अप्रमाणिक लोगों का विस्तार करता है।

  3. परिवर्तनशील संग्रह वर्गों का एक सेट, जो परस्पर इंटरफेस को लागू कर रहा है, और विस्तार द्वारा भी अपरिवर्तनीय इंटरफेस है।

  4. अपरिवर्तनीय संग्रह को लागू करने के लिए अपरिवर्तनीय संग्रह कक्षाओं का एक सेट , लेकिन ज्यादातर कक्षाओं के रूप में चारों ओर से गुजरता है, ताकि अपरिवर्तनीयता की गारंटी हो सके।

मैंने मस्ती के लिए उपरोक्त सभी को लागू किया है, और मैं उन्हें परियोजनाओं में उपयोग कर रहा हूं, और वे एक आकर्षण की तरह काम करते हैं।

कारण कि वे जावा रनटाइम का हिस्सा नहीं हैं क्योंकि शायद यह सोचा गया था कि यह बहुत अधिक / बहुत जटिल होगा / समझना बहुत मुश्किल होगा।

व्यक्तिगत रूप से, मुझे लगता है कि मैंने जो ऊपर वर्णित किया है, वह भी पर्याप्त नहीं है; एक और चीज़ जो ज़रूरी प्रतीत होती है वह है संरचनात्मक अपरिवर्तनशीलता के लिए उत्परिवर्तनीय इंटरफेस और कक्षाओं का एक समूह । (जिसे बस "कठोर" कहा जा सकता है क्योंकि उपसर्ग "स्ट्रक्चरललीम्यूटेबल" बहुत लंबा है।)


अच्छे अंक। दो विवरण: 1. अपरिवर्तनीय संग्रह के लिए कुछ विधि हस्ताक्षरों की आवश्यकता होती है, विशेष रूप से (उदाहरण के रूप में एक सूची का उपयोग करके): List<T> add(T t)- सभी "म्यूटेटर" विधियों को एक नया संग्रह लौटना चाहिए जो परिवर्तन को दर्शाता है। 2. बेहतर या बदतर के लिए, इंटरफेस अक्सर एक हस्ताक्षर के अलावा एक अनुबंध का प्रतिनिधित्व करते हैं । Serializable एक ऐसा इंटरफ़ेस है। इसी तरह, तुलनीय की आवश्यकता है कि आप सही ढंग compareTo()से काम करने के लिए अपनी पद्धति को सही ढंग से लागू करें और आदर्श रूप से संगत हों equals()और hashCode()
ग्लेनपेटर्सन

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

क्या आपका कार्यान्वयन सार्वजनिक रूप से उपलब्ध है? मुझे यह महीनों पहले पूछना चाहिए था। वैसे भी, मेरा है: github.com/GlenKPeterson/UncleJim
GlenPeterson

4
Suppose someone hands you such a read-only collection interface; is it safe to pass it to another thread?मान लीजिए कि कोई व्यक्ति आपको परिवर्तनशील संग्रह इंटरफ़ेस का उदाहरण देता है। क्या इस पर कोई विधि लागू करना सुरक्षित है? आपको पता नहीं है कि कार्यान्वयन हमेशा के लिए लूप नहीं करता है, एक अपवाद को फेंक दें, या इंटरफ़ेस के अनुबंध को पूरी तरह से अस्वीकृत कर देता है। विशेष रूप से अपरिवर्तनीय संग्रह के लिए एक डबल मानक क्यों है?
डोभाल

1
IMHO आपके परस्पर परिवर्तन के खिलाफ तर्क गलत है। आप अपरिवर्तनीय इंटरफेस के एक परिवर्तनशील कार्यान्वयन लिख सकते हैं, और फिर यह टूट जाता है। ज़रूर। लेकिन यह आपकी गलती है क्योंकि आप अनुबंध का उल्लंघन कर रहे हैं। बस ऐसा करना बंद करो। यह SortedSetएक गैर-अनुरूपण कार्यान्वयन के साथ सेट को तोड़कर अलग करने से अलग नहीं है । या एक असंगत पारित करके Comparable। अगर आप चाहें तो लगभग कुछ भी टूट सकता है। मुझे लगता है, कि @ डोवल का मतलब "दोहरे मापदंड" से है।
Maaartinus

2

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

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

उदाहरण: मेरे 4x1.6ghz लैपटॉप पर, मैं 500K हैशपॉल ऑप्स या 3M ऑप्स ऑफ़ लॉन्ग के मुकाबले 1K हैश चक्र (55 बाइट्स तक) में फिट होने वाले छोटे आकार के प्रति सेकंड 200K sha256s चला सकता हूं। 200K / लॉग (संग्रह करना) प्रति सेकंड नया संग्रह कुछ चीजों के लिए काफी तेज है जहां डेटा अखंडता और अनाम वैश्विक स्केलेबिलिटी महत्वपूर्ण है।


-3

प्रदर्शन। उनके स्वभाव से संग्रह बहुत बड़े हो सकते हैं। एक तत्व को सम्मिलित करने के बजाय 1001 तत्वों के साथ एक नई संरचना में 1000 तत्वों की नकल करना केवल सादा भयानक है।

संगामिति। यदि आपके पास कई थ्रेड चल रहे हैं, तो वे संग्रह का वर्तमान संस्करण प्राप्त करना चाहते हैं, न कि वह संस्करण जो 12 घंटे पहले पारित किया गया था जब धागा शुरू हुआ था।

भंडारण। एक बहु थ्रेडेड वातावरण में अपरिवर्तनीय वस्तुओं के साथ आप अपने जीवन चक्र के विभिन्न बिंदुओं पर "समान" ऑब्जेक्ट की दर्जनों प्रतियों के साथ समाप्त कर सकते हैं। एक कैलेंडर या दिनांक ऑब्जेक्ट के लिए कोई फर्क नहीं पड़ता, लेकिन जब 10,000 विजेट का एक संग्रह यह आपको मार देगा।


12
अपरिवर्तनीय संग्रह के लिए केवल नकल की आवश्यकता होती है यदि आप जावा जैसे व्यापक परिवर्तनशीलता के कारण साझा नहीं कर सकते हैं। कंज्यूरेबिल आमतौर पर अपरिवर्तनीय संग्रह के साथ आसान होता है क्योंकि उन्हें लॉकिंग की आवश्यकता नहीं होती है; और दृश्यता के लिए आप हमेशा एक अपरिवर्तनीय संग्रह (OCaml में आम) का एक परस्पर संदर्भ रख सकते हैं। साझा करने के साथ, अपडेट अनिवार्य रूप से मुफ्त हो सकते हैं। आप एक उत्परिवर्तनीय संरचना की तुलना में लॉगरिदमिक रूप से अधिक आवंटन कर सकते हैं, लेकिन अपडेट होने पर, कई एक्सपायर किए गए सबोबिज को तुरंत या पुन: उपयोग से मुक्त किया जा सकता है, इसलिए आपको आवश्यक रूप से अधिक मेमोरी ओवरहेड नहीं है।
जॉन प्यूरी

4
युगल समस्याएँ। क्लजुरे और स्काला में संग्रह दोनों अपरिवर्तनीय हैं, लेकिन हल्के वजन की प्रतियों का समर्थन करते हैं। 1001 तत्व जोड़ने का मतलब है 33 से कम तत्वों की नकल करना, साथ ही कुछ नए संकेत बनाना। यदि आप थ्रेड्स में एक परस्पर संग्रह साझा करते हैं, तो जब आप इसे बदलते हैं, तो आपके पास सभी प्रकार के सिंक्रनाइज़ेशन समस्याएँ होती हैं। "हटाओ ()" जैसे ऑपरेशन बुरे सपने हैं। इसके अलावा, अपरिवर्तनीय संग्रहों को पारस्परिक रूप से बनाया जा सकता है, फिर एक बार नकल करने के बाद धागे के पार साझा करने के लिए सुरक्षित एक अपरिवर्तनीय संस्करण में।
ग्लेनपेटर्सन

4
अपरिपक्वता के खिलाफ तर्क के रूप में संगामिति का उपयोग करना असामान्य है। साथ ही नकल करता है।
टॉम हॉकिन -

4
यहाँ नीचे वोटों के बारे में थोड़ा जानकारी मिली। ओपी ने पूछा कि वे अपरिवर्तनीय संग्रह क्यों लागू नहीं करते हैं, और, मैंने प्रश्न का एक उत्तर दिया। संभवत: फैशन के प्रति जागरूक लोगों के बीच एकमात्र स्वीकार्य उत्तर "क्योंकि उन्होंने गलती की है"। मैं वास्तव में इस के साथ कुछ अनुभव है क्योंकि कोड के बड़े खंड को फिर से भरने के लिए अन्यथा उत्कृष्ट BigDecimal वर्ग का उपयोग पूरी तरह से खराब perfomance की वजह से 512 बार अपरिवर्तनीयता के कारण होता है जो कि एक डबल प्लस का उपयोग करते हुए कुछ दशमलव को ठीक करने के लिए खिलवाड़ करता है।
जेम्स एंडरसन

3
@JamesAnderson: आपके जवाब के साथ मेरी समस्याएं: "प्रदर्शन" - आप कह सकते हैं कि वास्तविक जीवन अपरिवर्तनीय संग्रह हमेशा साझा करने के कुछ प्रकार को लागू करते हैं और आपके द्वारा बताए गए मुद्दे से बचने के लिए पुन: उपयोग करते हैं। "कॉन्सिक्वेंसी" - यह तर्क उबलता है "यदि आप परिवर्तनशीलता चाहते हैं, तो एक अपरिवर्तनीय वस्तु काम नहीं करती है।" मेरा मतलब है कि अगर "एक ही चीज़ के नवीनतम संस्करण" की धारणा है, तो कुछ को म्यूट करने की आवश्यकता है, या तो बात खुद की है, या कुछ और जो चीज का मालिक है। और "संग्रहण" में, आप कहते हैं कि उत्परिवर्तन कभी-कभी वांछित नहीं होता है।
झोमिनल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.