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

public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Thomas");
       cats[1] = new Cat("Behemoth");
       cats[2] = new Cat("Lionel Messi");

       cats[1] = null;

       System.out.println(Arrays.toString(cats));
   }

   
@Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
आउटपुट: [बिल्ली {नाम = 'थॉमस'}, अशक्त, बिल्ली {नाम = 'लियोनेल मेसी'}] लेकिन एक सरणी तत्व को अशक्त करने के लिए "छेद" छोड़ देता है। हमने सरणी में स्थिति नहीं हटाई है, केवल इसकी सामग्री हटा दी है। कल्पना कीजिए कि अगर हमारे पास 50 बिल्लियों की एक सरणी होती है और उनमें से 17 को इस तरह हटा दिया जाता है। हमारे पास 17 छेदों वाली एक सरणी होगी। बस उन पर नज़र रखने की कोशिश करें! खाली सेल की संख्या को याद रखने की उम्मीद करना अवास्तविक है जहां आप नए मान लिख सकते हैं। यदि आप एक गलती करते हैं, तो आप अपने इच्छित ऑब्जेक्ट संदर्भ को अधिलेखित कर देंगे। बेशक, इसे थोड़ा और सावधानी से करने का एक तरीका है: एक तत्व को हटाने के बाद, अंत में "छेद" डालने के लिए तत्वों को सरणी के सामने ले जाएं :

public static void main(String[] args) {

   Cat[] cats = new Cat[4];
   cats[0] = new Cat("Thomas");
   cats[1] = new Cat("Behemoth");
   cats[2] = new Cat("Lionel Messi");
   cats[2] = new Cat("Fluffy");

   cats[1] = null;

   for (int i = 2; i < cats.length-1; i++) {
       cats [i-1] = cats [i];// Move the elements to the front of the array, so the empty position is at the end
   }

   System.out.println(Arrays.toString(cats));
}
आउटपुट: [बिल्ली {नाम = 'थॉमस'}, बिल्ली {नाम = 'शराबी'}, बिल्ली {नाम = 'शराबी'}, अशक्त] यह बेहतर लगता है, लेकिन इसे शायद ही एक मजबूत समाधान कहा जा सकता है। यदि इस तथ्य के अलावा किसी अन्य कारण से नहीं कि हमें यह कोड हर बार लिखना पड़ता है जब हम किसी तत्व को किसी सरणी से हटाते हैं! यह एक बुरा विकल्प है। हम दूसरे तरीके से जा सकते हैं और एक अलग विधि बना सकते हैं:

public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
लेकिन यह भी बहुत कम उपयोग का है: यह विधि केवल वस्तुओं के साथ काम कर सकती है Cat, अन्य प्रकारों के साथ नहीं। दूसरे शब्दों में, यदि किसी प्रोग्राम में अन्य 100 वर्ग हैं जिन्हें हम सरणियों के साथ उपयोग करना चाहते हैं, तो हमें उनमें से प्रत्येक में समान तर्क के साथ समान विधि लिखनी होगी। यह कुल आपदा है -_- लेकिन ArrayListवर्ग इस समस्या को हल करता है! यह तत्वों को हटाने के लिए एक विशेष विधि लागू करता है:remove()

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);
   System.out.println(cats.toString());

   cats.remove(1);

   System.out.println(cats.toString());
}
हम अपने ऑब्जेक्ट के इंडेक्स को मेथड में पास करते हैं, जो इसे डिलीट कर देता है (बिल्कुल एक एरे की तरह)। विधि remove()की दो विशेष विशेषताएं हैं। सबसे पहले, यह "छेद" नहीं छोड़ता है। यह पहले से ही तत्वों को स्थानांतरित करने के लिए आवश्यक तर्क को लागू करता है जब एक तत्व को बीच से हटा दिया जाता है, जिसे हमने पहले स्वयं लिखा था। पिछले कोड से आउटपुट देखें:

[Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]

[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
हमने एक बिल्ली को बीच से हटा दिया, और बाकी को स्थानांतरित कर दिया गया ताकि कोई खाली जगह न रहे। दूसरा , यह न केवल सूचकांक (एक सामान्य सरणी की तरह) द्वारा वस्तुओं को हटा सकता है, बल्कि संदर्भ द्वारा भी :

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);
   System.out.println(cats.toString());

   cats.remove(lionel);

   System.out.println(cats.toString());
}
आउटपुट: [बिल्ली {नाम = 'थॉमस'}, बिल्ली {नाम = 'बेहेमोथ'}, बिल्ली {नाम = 'लियोनेल मेस्सी'}, बिल्ली {नाम = 'शराबी'}] [बिल्ली {नाम = 'थॉमस'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] यह बहुत सुविधाजनक हो सकता है यदि आप हमेशा वांछित वस्तु के सूचकांक का ट्रैक नहीं रखना चाहते हैं। ऐसा लगता है कि हमने सामान्य विलोपन का पता लगा लिया है। आइए अब इस स्थिति की कल्पना करें: हम अपनी सूची पर पुनरावृति करना चाहते हैं और एक विशिष्ट नाम वाली बिल्ली को हटाना चाहते हैं । ऐसा करने के लिए, हम एक तेज़ forलूप (जिसे for-प्रत्येक लूप भी कहा जाता है) का उपयोग करेंगे, जिसका परिचय हमें ऋषि के पाठों में मिला था:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   for (Cat cat: cats) {

       if (cat.name.equals("Behemoth")) {
           cats.remove(cat);
       }
   }

   System.out.println(cats);
}
कोड पूरी तरह तार्किक दिखता है। लेकिन परिणाम एक बड़ा आश्चर्य हो सकता है: थ्रेड में अपवाद "मुख्य" java.util.ConcurrentModificationException पर java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) पर java.util.ArrayList$Itr.next(ArrayList. java:831) Cat.main(Cat.java:25) पर किसी प्रकार की त्रुटि है, और यह स्पष्ट नहीं है कि ऐसा क्यों हुआ। इस प्रक्रिया में कई बारीकियां शामिल हैं जिन्हें संबोधित किया जाना चाहिए। यहां सामान्य नियम है जिसे आपको याद रखने की आवश्यकता है: आप एक साथ एक संग्रह पर पुनरावृति नहीं कर सकते हैं और इसके तत्वों को बदल सकते हैं। और हमारा तात्पर्य किसी भी प्रकार के परिवर्तन से है, केवल हटाने से नहीं। यदि आप बिल्ली हटाने को नई बिल्लियों को सम्मिलित करने के प्रयास से प्रतिस्थापित करते हैं, तो परिणाम वही होगा:

for (Cat cat: cats) {

   cats.add(new Cat("Salem Saberhagen"));
}

System.out.println(cats);
धागे में अपवाद "मुख्य" java.util.ConcurrentModificationException java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) पर java.util.ArrayList$Itr.next(ArrayList.java:831) पर Cat.main( Cat.java:25) हमने एक ऑपरेशन को दूसरे में बदल दिया, लेकिन नतीजा नहीं बदला: हमें वही ConcurrentModificationException मिलता है । यह ठीक तब होता है जब हम सूची पर पुनरावृति करते हुए सूची को बदलकर उपरोक्त नियम को तोड़ने का प्रयास करते हैं। जावा में, हमें एक संग्रह पर पुनरावृति करते समय वस्तुओं को हटाने के लिएएक इटरेटर (Iteratorवर्गIteratorतत्वों की सूची पर सुरक्षित रूप से पुनरावृति के लिए जिम्मेदार है। यह काफी सरल है, क्योंकि इसकी केवल 3 विधियाँ हैं:
  • hasNext()- सूची में अगला आइटम है या नहीं, या हम पहले से ही अंतिम तक पहुंच चुके हैं, इस पर निर्भर करते हुए सही या गलत रिटर्न देता है।
  • next()- सूची में अगला आइटम लौटाता है
  • remove()- सूची से किसी आइटम को हटा देता है
जैसा कि आप देख सकते हैं, इटेटरेटर हमारी जरूरतों के लिए तैयार किया गया है, और साथ ही इसके बारे में कुछ भी जटिल नहीं है। मान लीजिए कि हम यह जांचना चाहते हैं कि क्या हमारी सूची में कोई अगला तत्व है, और यदि है तो उसे प्रदर्शित करें:

Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list
  
   Cat nextCat = catIterator.next();// Get the next element
   System.out.println(nextCat);// Display it
}
आउटपुट: बिल्ली {नाम = 'थॉमस'} बिल्ली {नाम = 'बेहेमोथ'} बिल्ली {नाम = 'लियोनेल मेस्सी'} बिल्ली {नाम = 'शराबी'} जैसा कि आप देख सकते हैं, एक बनाने के लिए पहले से ही एक विशेष विधि लागू कर दी गई ArrayListहै पुनरावर्तक iterator():। इसके अतिरिक्त, ध्यान दें कि जब हम एक पुनरावर्तक बनाते हैं, तो हम उन वस्तुओं के वर्ग को निर्दिष्ट करते हैं जिनके साथ यह ( <Cat>) काम करेगा। लब्बोलुआब यह है कि एक इटरेटर हमारे मूल कार्य को आसानी से संभालता है। उदाहरण के लिए, "लियोनेल मेस्सी" नाम की बिल्ली को हटा दें:

Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list

   Cat nextCat = catIterator.next();// Get the next element
   if (nextCat.name.equals("Lionel Messi")) {
       catIterator.remove();// Delete the cat with the specified name
   }
}

System.out.println(cats);
आउटपुट: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}]remove() आपने देखा होगा कि हमने पुनरावर्तक की विधि में या तो सूचकांक या नाम निर्दिष्ट नहीं किया था ! इटेटरेटर जितना दिख सकता है उससे कहीं ज्यादा स्मार्ट है: remove()इटरेटर द्वारा लौटाए गए अंतिम तत्व को हटा देता है। जैसा कि आप देख सकते हैं, इसने वही किया जो हम चाहते थे :) सिद्धांत रूप में, यह वह सब कुछ है जो आपको किसी ArrayList. खैर, लगभग सब कुछ। अगले पाठ में, हम इस वर्ग के अंदर देखेंगे, और देखेंगे कि विभिन्न विधि कॉलों के दौरान वहाँ क्या होता है :) तब तक!