2009-06-11 12 views
5

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

Wrapper.java

import java.util.List; 
import java.util.Iterator; 

public class Wrapper implements Iterable<Double> 
{ 
    private final List<Double> list; 

    public Wrapper(List<Double> list) 
    { 
     this.list = list; 
    } 

    public Iterator<Double> iterator() 
    { 
     return getList().iterator(); 
    } 

    public List<Double> data() { return getList(); } 
} 

Algorithm.java

import java.util.Iterator; 
import java.util.Collection; 

public class Algorithm 
{ 
    public static double sum(Collection<Double> collection) 
    { 
     double sum = 0.0; 
     Iterator<Double> iterator = collection.iterator(); 

     // Throws NoSuchElementException if the Collection contains no elements 
     do 
     { 
      sum += iterator.next(); 
     } 
     while(iterator.hasNext()); 

     return sum; 
    } 
} 

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

ठीक है, उम्मीद है कि एक साधारण समाधान है जो मेरी चिंताओं को हल करेगा। मैं सिर्फ जावा में वापस आ रहा हूं, और सी ++ में कॉन्स से निपटने से पहले इन चीजों को कभी नहीं माना। अग्रिम में धन्यवाद!

ओह! एक और बात मैंने अभी सोचा है। मैं व्यावहारिक रूप से आंतरिक सूची की एक प्रति वापस नहीं कर सकता। सूची आमतौर पर सैकड़ों हजार तत्व शामिल होंगे।

उत्तर

23

आप Collections.unmodifiableList का उपयोग कर सकते हैं और डेटा विधि को संशोधित कर सकते हैं।

public List<Double> data() { return Collections.unmodifiableList(getList()); } 

जावाडोक से:

निर्दिष्ट सूची का एक unmodifiable दृश्य देता है। यह विधि मॉड्यूल को उपयोगकर्ताओं को "केवल पढ़ने के लिए" आंतरिक सूचियों तक पहुंच प्रदान करने की अनुमति देती है। लौटे सूची पर क्वेरी आपरेशनों निर्दिष्ट सूची करने के लिए "के माध्यम से पढ़ने", और सूची लौटे, प्रत्यक्ष किया जाए या इसके iterator के माध्यम से, एक UnsupportedOperationException में परिणाम को संशोधित करने के प्रयास करता है।

+0

बिल्कुल सही! मैंने यह नहीं देखा। धन्यवाद। –

+1

आपको अभी भी रैपर ऑब्जेक्ट के तरीके की देखभाल करना है: चूंकि सूची निर्माता को पास की जाती है, इसलिए कोड में कहीं और संदर्भ हो सकते हैं। यदि आप चाहते हैं कि रैपर वास्तव में अपरिवर्तनीय हो, तो आपको सूची की सामग्री कॉपी करनी होगी। –

5

जावा में अपरिवर्तनीय वर्ग की एक वाक्य रचनात्मक अवधारणा नहीं है। ऑपरेटर तक पहुंचने के लिए प्रोग्रामर के रूप में आप पर निर्भर है, लेकिन आपको हमेशा यह मानना ​​होगा कि कोई इसका दुरुपयोग करेगा।

वास्तव में अपरिवर्तनीय वस्तु लोगों को राज्य बदलने या राज्य चर बदलने के लिए उपयोग करने के लिए एक रास्ता प्रदान नहीं करती है जिसका उपयोग राज्य को बदलने के लिए किया जा सकता है। आपकी कक्षा अब अपरिवर्तनीय नहीं है।यह अपरिवर्तनीय बनाने के लिए

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

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

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

यहाँ अपरिवर्तनीय कक्षाएं बनाने पर कुछ सुझाव हैं। http://java.sun.com/docs/books/tutorial/essential/concurrency/imstrat.html

+0

मुझे वास्तव में एलेक्स बी के सुझाव पसंद हैं। जैसा कि मैंने अपनी पोस्ट में उल्लेख किया है, मैं * सूची * की एक प्रति वापस नहीं कर सकता। आपके उत्तर में, आप उल्लेख करते हैं कि आप सूची के एक अपरिवर्तनीय दृश्य को वापस करने की अनुशंसा नहीं करते हैं, जैसा कि एलेक्स ने सुझाव दिया था। क्या आप विस्तार से बता सकते हैं? –

+0

@ स्कॉट: प्रोग्रामिंग में एक सामान्य दृष्टिकोण है जो कहता है "अपने उपयोगकर्ताओं को आश्चर्य न करें" या "रनटाइम त्रुटियों में संकलन-समय त्रुटियों को प्राथमिकता दें"। यह आम तौर पर बेहतर है कि कंपाइलर को आपके उपयोगकर्ता के प्रोग्राम को उत्पादन में क्रैश करने की बजाय समस्या हो। एक अपरिवर्तनीय सूची के साथ, आप एक वैध सूची लौटाते हैं, तब तक सूची को तब तक पारित किया जा सकता है जब तक कि कोई इसे संशोधित करने का प्रयास नहीं करता है, तब तक अचानक "विस्फोट" हो सकता है। – Uri

+0

@ स्कॉट: यदि आपको एक सूची वापस करने की आवश्यकता है और इसे कॉपी नहीं कर सकता है, तो आपको यह लागत लेना होगा, यह रनटाइम अपवाद चीज है। लेकिन शायद आपके फ़ंक्शन "getUnmodifiableList" या उस तरह कुछ नामकरण करने पर विचार करें। मेरे शोध से पता चला है कि ज्यादातर लोग वास्तव में उन कार्यों के दस्तावेज़ों को कभी नहीं पढ़ेंगे जो सहज महसूस करते हैं, जैसे डेटा() – Uri

5

क्या आप Collections.unmodifiableList का उपयोग कर सकते हैं?

प्रलेखन के अनुसार, यह List के एक अपरिवर्तनीय (अपरिवर्तनीय) दृश्य को वापस कर देगा। यह UnsupportedOperationException फेंककर remove और add जैसी विधियों के उपयोग को रोक देगा।

हालांकि, मैं देख पा रहे हैं नहीं है कि यह सूची अपने आप में वास्तविक तत्वों के संशोधन पर रोक नहीं लगेगी, इसलिए मैं काफी यकीन है कि अगर यह पर्याप्त अपरिवर्तनीय है नहीं कर रहा हूँ। कम से कम सूची स्वयं संशोधित नहीं की जा सकती है।

एक उदाहरण है जहाँ ListunmodifiableList द्वारा वापस की आंतरिक मूल्यों अभी भी बदला जा सकता है है:

class MyValue { 
    public int value; 

    public MyValue(int i) { value = i; } 

    public String toString() { 
     return Integer.toString(value); 
    } 
} 

List<MyValue> l = new ArrayList<MyValue>(); 
l.add(new MyValue(10)); 
l.add(new MyValue(42)); 
System.out.println(l); 

List<MyValue> ul = Collections.unmodifiableList(l); 
ul.get(0).value = 33; 
System.out.println(l); 

आउटपुट:

[10, 42] 
[33, 42] 

क्या यह मूल रूप से पता चलता है कि डेटा में निहित है, तो है List पहले स्थान पर उत्परिवर्तनीय है, सूची की सामग्री को बदला जा सकता है, भले ही सूची स्वयं अपरिवर्तनीय हो।

+0

मेरी सूची में केवल अपरिवर्तनीय ऑब्जेक्ट्स होंगे जो संख्या वर्ग (उदा। इंटीजर, डबल इत्यादि) का विस्तार करती हैं। –

+0

आह, फिर प्रभावी जावा की सिफारिश करने के लिए :) – coobird

5

चीजें अपनी कक्षा में सही ढंग से अपरिवर्तनीय बनाने के लिए की एक संख्या हैं। मेरा मानना ​​है कि इस पर प्रभावी जावा में चर्चा की गई है।

जैसा कि कई अन्य उत्तरों में उल्लिखित है, list पर लौटने वाले इटरेटर के माध्यम से संशोधन को रोकने के लिए, Collections.unmodifiableList केवल पढ़ने योग्य इंटरफ़ेस प्रदान करता है। यदि यह एक म्यूटेबल क्लास था, तो आप डेटा कॉपी करना चाहते हैं ताकि यह ऑब्जेक्ट होने पर भी लौटाई गई सूची बदल न जाए।

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

कक्षा उप-वर्गीकृत है, इसलिए विधियों को ओवरराइड किया जा सकता है। तो कक्षा final बनाओ। बेहतर निर्माता के स्थान पर एक स्थिर निर्माण विधि प्रदान करें।

public final class Wrapper implements Iterable<Double> { 
    private final List<Double> list; 

    private Wrapper(List<Double> list) { 
     this.list = Collections.unmodifiableList(new ArrayList<Double>(list)); 
    } 

    public static Wrapper of(List<Double> list) { 
     return new Wrapper(list); 
    } 

    public Iterator<Double> iterator() { 
     return list.iterator(); 
    } 

    public List<Double> data() { 
     return list; 
    } 
} 

जावा के लिए सही स्थिति में टैब से बचने और ब्रेसिज़ डालने से भी मददगार होगा।

+0

+1 के बारे में चिंता करने की एक कम चीज़ है। :) – cwash

+0

जावा में ब्रेसिज़ के लिए वास्तव में "सही स्थिति" नहीं है। सी में से कहीं अधिक है। ब्रेसिज़ के लिए सही स्थिति वह स्थिति है जो कम से कम बग में होती है। –

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