CodeGym /Java Blog /Willekeurig /Een element verwijderen uit een ArrayList
John Squirrels
Niveau 41
San Francisco

Een element verwijderen uit een ArrayList

Gepubliceerd in de groep Willekeurig
Hoi! In de laatste les hebben we kennis gemaakt met de ArrayListklas, en geleerd hoe we de meest voorkomende operaties met deze klas kunnen uitvoeren. Daarnaast wezen we op een aantal verschillen tussen een ArrayListen een gewone array. Maar we hebben één onderwerp omzeild, namelijk hoe elementen uit een ArrayList. Dat gaan we nu bespreken. Een element verwijderen uit een ArrayList - 1We hebben al vermeld dat het verwijderen van elementen uit een gewone array niet erg handig is. Aangezien we het element zelf niet kunnen verwijderen, kunnen we alleen de waarde ervan "nullen" (instellen op nul):

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 + '\'' +
               '}';
   }
}
Uitvoer: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] Maar het instellen van een array-element op null laat een "gat" achter. We hebben de positie in de array niet verwijderd, alleen de inhoud ervan. Stel je voor wat er zou gebeuren als we een reeks van 50 katten hadden en er op deze manier 17 zouden verwijderen. We hebben een array met 17 holes. Probeer ze maar eens bij te houden! Het is onrealistisch om te verwachten dat je het aantal lege cellen onthoudt waarin je nieuwe waarden kunt schrijven. Als u één fout maakt, overschrijft u een gewenste objectreferentie. Er is natuurlijk een manier om dit wat voorzichtiger te doen: nadat je een element hebt verwijderd, verplaats je de elementen naar de voorkant van de array om het "gat" aan het einde te plaatsen:

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));
}
Uitvoer: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] Dit lijkt beter, maar het kan nauwelijks een robuuste oplossing worden genoemd. Alleen al omdat we deze code elke keer moeten schrijven als we een element uit een array verwijderen! Dit is een slechte optie. We kunnen een andere weg inslaan en een aparte methode maken:

public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
Maar ook dit heeft weinig zin: deze methode werkt alleen met Catobjecten, maar niet met andere typen. Met andere woorden, als een programma nog eens 100 klassen heeft die we met arrays willen gebruiken, moeten we dezelfde methode schrijven met exact dezelfde logica in elk daarvan. Dit is een totale ramp -_- Maar de ArrayListklas lost dit probleem op! Het implementeert een speciale methode voor het verwijderen van elementen: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());
}
We geven de index van ons object door aan de methode, die deze verwijdert (net als in een array). De remove()methode heeft twee bijzondere kenmerken. Ten eerste laat het geen "gaten" achter. Het implementeert al de logica die nodig is om elementen te verschuiven wanneer een element uit het midden wordt verwijderd, wat we eerder zelf schreven. Kijk naar de uitvoer van de vorige code:

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

[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
We hebben één kat uit het midden verwijderd en de rest is verplaatst zodat er geen lege ruimtes waren. Ten tweede kan het objecten niet alleen per index verwijderen (zoals een normale array), maar ook per referentie :

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());
}
Uitvoer: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Dit kan erg handig zijn als je niet altijd de index van het gewenste object wilt bijhouden. Het lijkt erop dat we gewone verwijdering hebben ontdekt. Laten we ons nu deze situatie voorstellen: we willen onze lijst herhalen en een kat met een specifieke naam verwijderen . Om dit te doen, gebruiken we een snelle forlus (ook wel een for-each-lus genoemd), waarmee we in Rishi's lessen kennis hebben gemaakt:

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);
}
De code ziet er volkomen logisch uit. Maar het resultaat kan een grote verrassing zijn: uitzondering in thread "main" java.util.ConcurrentModificationException op java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) op java.util.ArrayList$Itr.next(ArrayList. java:831) bij Cat.main(Cat.java:25) Er is een soort fout opgetreden en het is onduidelijk waarom deze is opgetreden. Dit proces omvat een aantal nuances die moeten worden aangepakt. Dit is de algemene regel die u moet onthouden: u kunt niet tegelijkertijd een verzameling herhalen en de elementen ervan wijzigen. En we bedoelen elke vorm van verandering, niet alleen verwijdering. Als u het verwijderen van de kat vervangt door een poging om nieuwe katten in te brengen, is het resultaat hetzelfde:

for (Cat cat: cats) {

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

System.out.println(cats);
Uitzondering in thread "main" java.util.ConcurrentModificationException op java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) op java.util.ArrayList$Itr.next(ArrayList.java:831) op Cat.main( Cat.java:25) We hebben de ene bewerking in de andere gewijzigd, maar het resultaat is niet veranderd: we krijgen dezelfde ConcurrentModificationException . Het gebeurt precies wanneer we proberen de bovenstaande regel te overtreden door de lijst te wijzigen terwijl we eroverheen herhalen. In Java hebben we een speciaal object nodig, een iterator (Iteratorclass) genaamd, om items te verwijderen tijdens het herhalen van een verzameling. DeIteratorklasse is verantwoordelijk voor het veilig herhalen van de lijst met elementen. Het is vrij eenvoudig, omdat het slechts 3 methoden heeft:
  • hasNext()- retourneert waar of onwaar, afhankelijk van of er een volgend item in de lijst is, of dat we het laatste item al hebben bereikt.
  • next()- retourneert het volgende item in de lijst
  • remove()- verwijdert een item uit de lijst
Zoals u kunt zien, is de iterator op maat gemaakt voor onze behoeften, en tegelijkertijd is er niets ingewikkelds aan. Stel dat we willen controleren of er een volgend element in onze lijst staat, en het weergeven als er is:

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
}
Uitvoer: Cat{name='Thomas'} Cat{name='Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} Zoals je kunt zien, heeft het al een speciale ArrayListmethode geïmplementeerd voor het maken van een herhaling: iterator(). Houd er bovendien rekening mee dat wanneer we een iterator maken, we de klasse objecten opgeven waarmee deze zal werken ( <Cat>). Het komt erop neer dat een iterator onze oorspronkelijke taak gemakkelijk aankan. Verwijder bijvoorbeeld de kat met de naam "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);
Uitvoer: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Het is je misschien opgevallen dat we de index of de naam niet specificeerden in de remove()iteratormethode ! De iterator is slimmer dan het lijkt: remove()verwijdert het laatste element dat door de iterator wordt geretourneerd. Zoals je kunt zien, deed het precies wat we wilden :) In principe is dit alles wat je moet weten over het verwijderen van elementen uit een ArrayList. Nou ja, bijna alles. In de volgende les kijken we in deze klas en zien we wat daar gebeurt tijdens verschillende methodeaanroepen :) Tot dan!
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION