CodeGym /Blog Java /Aleatoriu /Ștergerea unui element dintr-o ArrayList
John Squirrels
Nivel
San Francisco

Ștergerea unui element dintr-o ArrayList

Publicat în grup
Bună! În ultima lecție, ne-am familiarizat cu ArrayListclasa și am învățat cum să efectuăm cele mai comune operațiuni cu această clasă. În plus, am subliniat câteva diferențe între o ArrayListmatrice obișnuită și o matrice obișnuită. Dar am ocolit un subiect, și anume, cum să ștergem elemente dintr-un ArrayList. Vom discuta asta acum. Ștergerea unui element dintr-o ArrayList - 1Am menționat deja că ștergerea elementelor dintr-o matrice obișnuită nu este foarte convenabilă. Deoarece nu putem șterge elementul în sine, putem doar să „zero out” (setat la nul) valoarea acestuia:

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 + '\'' +
               '}';
   }
}
Ieșire: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] Dar setarea unui element de matrice la null lasă o „gaură”. Nu am eliminat poziția din matrice, ci doar conținutul acesteia. Imaginați-vă ce s-ar întâmpla dacă am avea o serie de 50 de pisici și am elimina 17 dintre ele în acest fel. Vom avea o matrice cu 17 găuri. Încercați doar să le urmăriți! Este nerealist să vă așteptați să vă amintiți numărul de celule goale în care puteți scrie valori noi. Dacă faceți o greșeală, veți suprascrie o referință de obiect pe care o doriți. Există, desigur, o modalitate de a face acest lucru puțin mai atent: după îndepărtarea unui element, mutați elementele în partea din față a matricei pentru a pune „gaura” la sfârșit:

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));
}
Ieșire: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] Aceasta pare mai bună, dar cu greu poate fi numită o soluție robustă. Dacă nu din alt motiv decât faptul că trebuie să scriem acest cod de fiecare dată când ștergem un element dintr-o matrice! Aceasta este o opțiune proastă. Am putea merge pe altă cale și am crea o metodă separată:

public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
Dar și acest lucru este de puțin folos: această metodă poate funcționa numaiCat cu obiecte, dar nu și cu alte tipuri. Cu alte cuvinte, dacă un program are alte 100 de clase pe care dorim să le folosim cu tablouri, va trebui să scriem aceeași metodă cu exact aceeași logică în fiecare dintre ele. Acesta este un dezastru total -_- Dar ArrayListclasa rezolvă această problemă! Implementează o metodă specială pentru eliminarea elementelor: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());
}
Trecem indexul obiectului nostru metodei, care îl șterge (la fel ca într-o matrice). Metoda remove()are două caracteristici speciale. În primul rând, nu lasă „găuri”. Implementează deja logica necesară pentru deplasarea elementelor atunci când un element este îndepărtat din mijloc, ceea ce am scris-o noi înșine anterior. Priviți rezultatul din codul anterior:

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

[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
Am scos o pisică din mijloc, iar restul au fost mutate astfel încât să nu existe spații goale. În al doilea rând , poate șterge obiecte nu numai prin index (ca o matrice normală), ci și prin referință :

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());
}
Ieșire: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Acest lucru poate fi foarte convenabil dacă nu doriți să urmăriți întotdeauna indexul obiectului dorit. Se pare că ne-am dat seama de ștergerea obișnuită. Acum să ne imaginăm această situație: vrem să iterăm peste lista noastră și să eliminăm o pisică cu un nume specific . Pentru a face acest lucru, vom folosi o forbuclă rapidă (numită și buclă pentru fiecare), care ne-a fost introdus în lecțiile lui Rishi:

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);
}
Codul pare perfect logic. Dar rezultatul ar putea fi o mare surpriză: excepție în firul „principal” java.util.ConcurrentModificationException la java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) la java.util.ArrayList$Itr.next(ArrayList. java:831) la Cat.main(Cat.java:25) Există un fel de eroare și nu este clar de ce a apărut. Acest proces implică o serie de nuanțe care trebuie abordate. Iată regula generală pe care trebuie să o rețineți: nu puteți repeta simultan asupra unei colecții și nu puteți modifica elementele acesteia. Și ne referim la orice fel de schimbare, nu doar la eliminare. Dacă înlocuiți îndepărtarea pisicii cu o încercare de a introduce pisici noi, rezultatul va fi același:

for (Cat cat: cats) {

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

System.out.println(cats);
Excepție în firul „principal” java.util.ConcurrentModificationException la java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) la java.util.ArrayList$Itr.next(ArrayList.java:831) la Cat.main( Cat.java:25) Am schimbat o operație cu alta, dar rezultatul nu s-a schimbat: obținem aceeași ConcurrentModificationException . Apare exact atunci când încercăm să încălcăm regula de mai sus, schimbând lista în timp ce o iterăm. În Java, avem nevoie de un obiect special numit iterator (Iteratorclasă) pentru a șterge elemente în timp ce iterăm peste o colecție. ClasaIteratoreste responsabilă pentru iterarea în siguranță a listei de elemente. Este destul de simplu, deoarece are doar 3 metode:
  • hasNext()- returnează adevărat sau fals, în funcție de dacă există un articol următor în listă, sau am ajuns deja la ultimul.
  • next()- returnează următorul articol din listă
  • remove()- elimină un element din listă
După cum puteți vedea, iteratorul este adaptat nevoilor noastre și, în același timp, nu este nimic complicat. Să presupunem că vrem să verificăm dacă există un element următor în lista noastră și să-l afișăm dacă există:

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
}
Ieșire: Cat{name='Thomas'} Cat{name='Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} După cum puteți vedea, a implementat deja o metodă ArrayListspecială pentru crearea unui iterator: iterator(). În plus, rețineți că atunci când creăm un iterator, specificăm clasa de obiecte cu care va funcționa ( <Cat>). Concluzia este că un iterator se ocupă cu ușurință de sarcina noastră inițială. De exemplu, eliminați pisica numită „Lionel Messi”:

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);
Rezultat: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Esteremove() posibil să fi observat că nu am specificat nici indexul, nici numele în metoda iteratorului ! Iteratorul este mai inteligent decât ar putea părea: remove()elimină ultimul element returnat de iterator. După cum puteți vedea, a făcut exact ceea ce am vrut noi să facă :) În principiu, acesta este tot ce trebuie să știți despre eliminarea elementelor dintr-un ArrayList. Ei bine, aproape totul. În lecția următoare, ne vom uita în interiorul acestei clase și vom vedea ce se întâmplă acolo în timpul diferitelor apeluri de metodă :) Până atunci!
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION