जावा में अपरिवर्तनीय सरणी


158

क्या जावा में आदिम सरणियों के लिए एक अपरिवर्तनीय विकल्प है? एक आदिम सरणी बनाना finalवास्तव में किसी को कुछ करने से नहीं रोकता है

final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;

मैं चाहता हूं कि सरणी के तत्व अपरिवर्तनीय हों।


43
अपने आप को एक एहसान करो और 1 के अलावा कुछ के लिए जावा में सरणियों का उपयोग करना बंद करो) io 2) भारी संख्या में क्रंचिंग 3) यदि आपको अपनी सूची / संग्रह (जो दुर्लभ है ) लागू करने की आवश्यकता है । वे बेहद अनम्य और पुरातन हैं ... जैसा कि आपने इस प्रश्न के साथ खोजा है।
व्हेल

39
@Whaley, और प्रदर्शन, और कोड जहां आपको "गतिशील" सरणियों की आवश्यकता नहीं है। Arrays अभी भी बहुत सी जगहों पर उपयोगी है, यह उतना दुर्लभ नहीं है।
कॉलिन हेबर्ट सेप

10
@ कोलिन: हाँ, लेकिन वे गंभीर रूप से विवश हैं; यह सोचने की आदत में आना सबसे अच्छा है "क्या मुझे वास्तव में यहां एक सरणी की आवश्यकता है या मैं इसके बजाय एक सूची का उपयोग कर सकता हूं?"
जेसन एस

7
@ कोलिन: केवल जब आप की जरूरत है अनुकूलन। जब आप अपने आप को आधा मिनट कुछ ऐसा जोड़ते हुए पाते हैं, उदाहरण के लिए, एक सरणी को बड़ा करता है या आप कुछ इंडेक्स को फॉर-लूप के दायरे से बाहर रखते हैं, तो आप पहले से ही अपने बॉस का कुछ समय बर्बाद कर चुके हैं। सबसे पहले बनाएँ, कब और कहाँ इसकी आवश्यकता है - और अधिकांश अनुप्रयोगों में, यह सरणियों के साथ सूचियों को प्रतिस्थापित करने में नहीं है।
fwielstra

9
क्यों, किसी ने उल्लेख नहीं किया int[]और new int[]क्या MUCH टाइप करना आसान है List<Integer>और new ArrayList<Integer>? XD
lcn

जवाबों:


164

आदिम सरणियों के साथ नहीं। आपको सूची या कुछ अन्य डेटा संरचना का उपयोग करने की आवश्यकता होगी:

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));

18
किसी तरह मैं कभी Arrays.asList (T ...) के बारे में नहीं जानता था। मुझे लगता है कि मैं अब अपने ListUtils.list (T ...) से छुटकारा पा सकता हूं।
21

3
वैसे, Arrays.asList एक
असंसदीय

3
@ यह है कि ArrayList java.util का नहीं है
mauhiz

11
@mauhiz Arrays.asListहै नहीं unmodifiable। docs.oracle.com/javase/7/docs/api/java/util/… "निर्दिष्ट सरणी द्वारा समर्थित निश्चित आकार की सूची लौटाता है। (लौटी सूची में परिवर्तन" सरणी के लिए "के माध्यम से लिखें")
जेसन एस

7
@JasonS ठीक है, Arrays.asList()वास्तव में लगता है अर्थ में unmodifiable कि आप नहीं कर सकते addया removeकी लौटे आइटम java.util.Arrays.ArrayList( भ्रमित होने की नहीं के साथ java.util.ArrayList) - इन आपरेशनों बस से लागू नहीं कर रहे हैं। शायद @mauhiz यह कहने की कोशिश करता है? लेकिन निश्चित रूप से आप मौजूदा तत्वों को संशोधित कर सकते हैं List<> aslist = Arrays.asList(...); aslist.set(index, element), इसलिए java.util.Arrays.ArrayListनिश्चित रूप से अकारण नहीं है , QED ने टिप्पणी को asListसामान्य और परिणाम के बीच अंतर पर जोर देने के लिए जोड़ाArrayList
NIA

73

मेरे सिफारिश किसी सरणी या एक का उपयोग नहीं करने के लिए है unmodifiableList, लेकिन उपयोग करने के लिए अमरूद के ImmutableList है, जो इस उद्देश्य के लिए मौजूद है।

ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);

3
+1 अमरूद का इम्युनटेबलिस्ट कलेक्शन से बेहतर है।
sleske

29
ImmutableList अक्सर बेहतर होता है (यह उपयोग के मामले पर निर्भर करता है) क्योंकि यह अपरिवर्तनीय है। संग्रह। बल्कि, यह एक ऐसा दृश्य है जो रिसीवर नहीं बदल सकता है, लेकिन मूल स्रोत बदल सकता है।
चार्ली कॉलिन्स

2
@CharlieCollins, अगर Collections.unmodifiableListसूची को अपरिवर्तनीय बनाने के लिए पर्याप्त मूल स्रोत तक पहुंचने का कोई तरीका नहीं है ?
सावनभारत

1
@savanibharat हां।
बस एक छात्र

20

जैसा कि अन्य ने उल्लेख किया है, आपके पास जावा में अपरिवर्तनीय सरणियाँ नहीं हो सकती हैं।

यदि आपको पूरी तरह से एक ऐसी विधि की आवश्यकता है जो एक सरणी देता है जो मूल सरणी को प्रभावित नहीं करती है, तो आपको हर बार सरणी को क्लोन करने की आवश्यकता होगी:

public int[] getFooArray() {
  return fooArray == null ? null : fooArray.clone();
}

स्पष्ट रूप से यह महंगा है (जैसा कि आप हर बार जब आप कॉल करने वाले को कॉल करते हैं) एक पूरी कॉपी बना लेंगे, लेकिन अगर आप इंटरफ़ेस को नहीं बदल सकते हैं ( Listउदाहरण के लिए उपयोग करने के लिए) और क्लाइंट को अपने इंटर्नल को बदलने का जोखिम नहीं उठा सकते हैं, तो यह आवश्यक हो सकता है।

इस तकनीक को रक्षात्मक प्रतिलिपि बनाना कहा जाता है।


3
उन्होंने कहां उल्लेख किया है कि उन्हें एक गटर की आवश्यकता है?
एरिक रॉबर्टसन

6
@ एरिक: उन्होंने ऐसा नहीं किया, लेकिन यह अपरिवर्तनीय डेटा संरचनाओं के लिए एक बहुत ही सामान्य उपयोग का मामला है (मैंने सामान्य रूप से तरीकों को संदर्भित करने के लिए उत्तर को संशोधित किया, क्योंकि समाधान हर जगह लागू होता है, भले ही यह गेटर्स में अधिक सामान्य हो)।
जोआचिम सॉयर

7
क्या इसका उपयोग करना बेहतर है clone()या Arrays.copy()यहां?
केविनरपे

जहाँ तक मुझे याद है, यहोशू बलोच के "प्रभावी जावा" के अनुसार, क्लोन () निश्चित रूप से पसंदीदा तरीका है।
विंसेंट

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

14

जावा में एक अपरिवर्तनीय सारणी बनाने का एक तरीका है:

final String[] IMMUTABLE = new String[0];

0 तत्वों (स्पष्ट रूप से) के साथ ऐरे को म्यूट नहीं किया जा सकता है।

यह वास्तव में काम में आ सकता है यदि आप किसी ऐरे में List.toArrayबदलने के लिए विधि का उपयोग कर रहे हैं List। चूँकि एक खाली सरणी भी कुछ मेमोरी लेती है, आप एक निरंतर खाली सरणी बनाकर और हमेशा इसे toArrayविधि में पास करके उस मेमोरी आवंटन को बचा सकते हैं । यदि आप जिस पास से गुजरते हैं उसके पास पर्याप्त स्थान नहीं है, तो यह विधि एक नई सरणी आवंटित करेगी, लेकिन यदि यह (सूची खाली है), तो यह आपके द्वारा पास किए गए सरणी को वापस कर देगा, जिससे आप किसी भी समय कॉल toArrayपर उस सरणी का पुन: उपयोग कर सकेंगे। खाली List

final static String[] EMPTY_STRING_ARRAY = new String[0];

List<String> emptyList = new ArrayList<String>();
return emptyList.toArray(EMPTY_STRING_ARRAY); // returns EMPTY_STRING_ARRAY

3
लेकिन यह ओपी को इसमें डेटा के साथ एक अपरिवर्तनीय सरणी प्राप्त करने में मदद नहीं करता है।
श्रीधर सरनोबत

1
@ श्रीधर-सरनोबत जवाब की तरह है। इसमें डेटा के साथ एक अपरिवर्तनीय सरणी बनाने के लिए जावा में कोई रास्ता नहीं है।
ब्रिघम

1
मुझे यह सरल वाक्यविन्यास बेहतर लगता है: निजी स्थिर अंतिम स्ट्रिंग [] EMPTY_STRING_ARRAY = {}; (जाहिर है मुझे नहीं पता है कि "मिनी-मार्कडाउन" कैसे करना है। एक पूर्वावलोकन बटन अच्छा होगा।)
वेस

6

एक और जवाब

static class ImmutableArray<T> {
    private final T[] array;

    private ImmutableArray(T[] a){
        array = Arrays.copyOf(a, a.length);
    }

    public static <T> ImmutableArray<T> from(T[] a){
        return new ImmutableArray<T>(a);
    }

    public T get(int index){
        return array[index];
    }
}

{
    final ImmutableArray<String> sample = ImmutableArray.from(new String[]{"a", "b", "c"});
}

कंस्ट्रक्टर में उस एरे को कॉपी करने का क्या उपयोग है, क्योंकि हमने कोई सेटर विधि प्रदान नहीं की है?
विजया कुमार

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

4

जावा 9 के रूप में आप उपयोग कर सकते हैं List.of(...), JavaDoc

यह विधि एक अपरिवर्तनीय रिटर्न देती है Listऔर बहुत ही कुशल है।


3

यदि आपको। Java.lang.Integer ’के बजाय मूल प्रदर्शन (मेमोरी कारण या मेमोरी को बचाने के लिए) की आवश्यकता है, तो आपको संभवतः अपना स्वयं का रैपर क्लास लिखने की आवश्यकता होगी। नेट पर विभिन्न इंटेरियर कार्यान्वयन हैं, लेकिन कोई भी (मुझे नहीं मिला) अपरिवर्तनीय था: कोडर्स इंट्रे , ल्यूसिन इंट्रे । शायद अन्य हैं।


3

अमरूद 22 के बाद से, पैकेज से com.google.common.primitivesआप तीन नए वर्गों का उपयोग कर सकते हैं, जिनकी तुलना में कम मेमोरी के पदचिह्न हैं ImmutableList

उनका एक बिल्डर भी है। उदाहरण:

int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
  .add(1L)
  .add(2L)
  .build();

या, यदि आकार संकलन-समय पर जाना जाता है:

ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);

यह जावा आदिम के लिए एक सरणी का एक अपरिवर्तनीय दृश्य प्राप्त करने का एक और तरीका है।


1

नहीं, यह संभव नहीं है। हालाँकि, कुछ इस तरह कर सकता है:

List<Integer> temp = new ArrayList<Integer>();
temp.add(Integer.valueOf(0));
temp.add(Integer.valueOf(2));
temp.add(Integer.valueOf(3));
temp.add(Integer.valueOf(4));
List<Integer> immutable = Collections.unmodifiableList(temp);

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


4
उन सभी को लिखने की आवश्यकता नहीं है valueOf(), ऑटोबॉक्सिंग उस का ध्यान रखेगा। यह भी Arrays.asList(0, 2, 3, 4)अधिक संक्षिप्त होगा।
जोआचिम सॉर

@ जोचिम: valueOf()मेमोरी की खपत / पुनर्चक्रण को कम करने के लिए आंतरिक इंटेगर ऑब्जेक्ट कैश का उपयोग करने का बिंदु है ।
एस्स्को

4
@ एस्को: ऑटोबॉक्सिंग कल्पना पढ़ें। यह बिल्कुल वैसा ही काम करता है, इसलिए यहां कोई अंतर नहीं है।
जोकिम सॉयर

1
@ जॉन आप एक एनपीई एक परिवर्तित कभी नहीं मिलेगा intएक करने के लिए Integerहालांकि, बस आसपास के दूसरे तरीके से सावधान रहना होगा।
कोलिनड

1
@ जॉन: आप सही कह रहे हैं, यह खतरनाक हो सकता है। लेकिन इसे पूरी तरह से टालने के बजाय, खतरे को समझना और उससे बचना शायद बेहतर है।
जोकिम सॉयर

1

कुछ स्थितियों में, Google Guava लाइब्रेरी से इस स्थिर विधि का उपयोग करने के लिए यह हल्का वजन होगा: List<Integer> Ints.asList(int... backingArray)

उदाहरण:

  • List<Integer> x1 = Ints.asList(0, 1, 2, 3)
  • List<Integer> x1 = Ints.asList(new int[] { 0, 1, 2, 3})

1

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


1

के (ई ... तत्व) में विधि Java9 सिर्फ एक लाइन का उपयोग अपरिवर्तनीय सूची बनाने के लिए इस्तेमाल किया जा सकता:

List<Integer> items = List.of(1,2,3,4,5);

उपरोक्त विधि एक अपरिवर्तनीय सूची देता है जिसमें तत्वों की एक मनमानी संख्या होती है। और इस सूची में किसी भी पूर्णांक को जोड़ने से java.lang.UnsupportedOperationExceptionअपवाद होगा। यह विधि एकल सरणी को एक तर्क के रूप में भी स्वीकार करती है।

String[] array = ... ;
List<String[]> list = List.<String[]>of(array);

0

हालांकि यह सच है कि Collections.unmodifiableList()काम करता है, कभी-कभी आपके पास एक बड़ा पुस्तकालय हो सकता है जिसमें पहले से ही रिटर्न एरे (जैसे String[]) को परिभाषित करने के तरीके हैं । उन्हें तोड़ने से रोकने के लिए, आप वास्तव में सहायक सरणियों को परिभाषित कर सकते हैं जो मूल्यों को संग्रहीत करेंगे:

public class Test {
    private final String[] original;
    private final String[] auxiliary;
    /** constructor */
    public Test(String[] _values) {
        original = new String[_values.length];
        // Pre-allocated array.
        auxiliary = new String[_values.length];
        System.arraycopy(_values, 0, original, 0, _values.length);
    }
    /** Get array values. */
    public String[] getValues() {
        // No need to call clone() - we pre-allocated auxiliary.
        System.arraycopy(original, 0, auxiliary, 0, original.length);
        return auxiliary;
    }
}

परीक्षा करना:

    Test test = new Test(new String[]{"a", "b", "C"});
    System.out.println(Arrays.asList(test.getValues()));
    String[] values = test.getValues();
    values[0] = "foobar";
    // At this point, "foobar" exist in "auxiliary" but since we are 
    // copying "original" to "auxiliary" for each call, the next line
    // will print the original values "a", "b", "c".
    System.out.println(Arrays.asList(test.getValues()));

सही नहीं है, लेकिन कम से कम आपके पास "छद्म अपरिवर्तनीय सरणियाँ" (वर्ग के नजरिए से) हैं और इससे संबंधित कोड नहीं टूटेगा।


-3

खैर .. सरणियाँ स्थिरांक के रूप में पारित करने के लिए उपयोगी हैं (यदि वे थे) वेरिएंट मापदंडों के रूप में।


"वेरिएंट पैरामीटर" क्या है? कभी नहीं सुना।
sleske

2
स्थिरांक के रूप में सरणियों का उपयोग करना बिल्कुल वही है जहां बहुत से लोग विफल होते हैं। संदर्भ स्थिर है, लेकिन सरणी की सामग्री परस्पर हैं। एक कॉलर / क्लाइंट आपके "स्थिर" की सामग्री को बदल सकता है। यह संभवत: कुछ ऐसा नहीं है जिसे आप अनुमति देना चाहते हैं। एक ImmutableList का उपयोग करें।
चार्ली कॉलिन्स

@CharlieCollins को भी प्रतिबिंब के माध्यम से हैक किया जा सकता है। जावा परिवर्तनशीलता के संदर्भ में असुरक्षित भाषा है ... और यह बदलने वाला नहीं है।
नाम

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