CodeGym /Java blogg /Slumpmässig /Ta bort ett element från en ArrayList
John Squirrels
Nivå
San Francisco

Ta bort ett element från en ArrayList

Publicerad i gruppen
Hej! På förra lektionen bekantade vi oss med klassen, ArrayListoch lärde oss hur man utför de vanligaste operationerna med denna klass. Dessutom påpekade vi flera skillnader mellan en ArrayListoch en vanlig array. Men vi gick över ett ämne, nämligen hur man tar bort element från en ArrayList. Vi ska diskutera det nu. Ta bort ett element från en ArrayList - 1Vi har redan nämnt att det inte är särskilt bekvämt att ta bort element från en vanlig array. Eftersom vi inte kan ta bort själva elementet kan vi bara "nolla ut" (ställ in på null) dess värde:

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 + '\'' +
               '}';
   }
}
Utdata: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] Men att ställa in ett array-element till null lämnar ett "hål". Vi har inte tagit bort positionen i arrayen, bara dess innehåll. Föreställ dig vad som skulle hända om vi hade en samling av 50 katter och tog bort 17 av dem på detta sätt. Vi kommer att ha en array med 17 hål. Försök bara hålla reda på dem! Det är orealistiskt att förvänta sig att komma ihåg antalet tomma celler där du kan skriva nya värden. Om du gör ett misstag kommer du att skriva över en objektreferens som du vill ha. Det finns naturligtvis ett sätt att göra detta lite mer noggrant: efter att ha tagit bort ett element, flytta elementen till framsidan av arrayen för att sätta "hålet" i slutet:

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));
}
Utdata: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] Detta verkar bättre, men det kan knappast kallas en robust lösning. Om inte annat för att vi måste skriva denna kod varje gång vi tar bort ett element från en array! Detta är ett dåligt alternativ. Vi skulle kunna gå en annan väg och skapa en separat metod:

public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
Men detta är också till liten nytta: den här metoden kan bara fungera med Catobjekt, men inte andra typer. Med andra ord, om ett program har ytterligare 100 klasser som vi vill använda med arrayer, måste vi skriva samma metod med exakt samma logik i var och en av dem. Detta är en total katastrof -_- Men ArrayListklassen löser detta problem! Den implementerar en speciell metod för att ta bort element: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());
}
Vi skickar vårt objekts index till metoden, som tar bort det (precis som i en array). Metoden remove()har två speciella egenskaper. För det första lämnar det inga "hål". Den implementerar redan logiken som behövs för att flytta element när ett element tas bort från mitten, vilket vi tidigare skrev själva. Titta på resultatet från föregående kod:

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

[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
Vi tog bort en katt från mitten, och resten flyttades så att det inte fanns några tomma utrymmen. För det andra kan den radera objekt inte bara genom index (som en normal array), utan också genom referens :

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());
}
Utdata: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Detta kan vara väldigt praktiskt om du inte alltid vill hålla reda på det önskade objektets index. Det verkar som om vi har räknat ut vanlig radering. Låt oss nu föreställa oss den här situationen: vi vill upprepa vår lista och ta bort en katt med ett specifikt namn . För att göra detta kommer vi att använda en snabb forloop (även kallad en för varje loop), som vi introducerades för i Rishis lektioner:

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);
}
Koden ser helt logisk ut. Men resultatet kan bli en stor överraskning: Undantag i tråden "main" java.util.ConcurrentModificationException på java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) på java.util.ArrayList$Itr.next(ArrayList. java:831) på Cat.main(Cat.java:25) Det finns något slags fel, och det är oklart varför det inträffade. Denna process innebär ett antal nyanser som måste åtgärdas. Här är den allmänna regeln du måste komma ihåg: Du kan inte samtidigt iterera över en samling och ändra dess element. Och vi menar vilken typ av förändring som helst, inte bara borttagning. Om du ersätter kattborttagningen med ett försök att sätta in nya katter blir resultatet detsamma:

for (Cat cat: cats) {

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

System.out.println(cats);
Undantag i tråden "main" java.util.ConcurrentModificationException vid java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) på java.util.ArrayList$Itr.next(ArrayList.java:831) på Cat.main( Cat.java:25) Vi ändrade en operation till en annan, men resultatet ändrades inte: vi får samma ConcurrentModificationException . Det inträffar precis när vi försöker bryta regeln ovan genom att ändra listan medan vi itererar över den. I Java behöver vi ett speciellt objekt som kallas en iterator (Iteratorklass) för att radera objekt medan vi itererar över en samling. KlassenIteratoransvarar för att säkert iterera över listan med element. Det är ganska enkelt, eftersom det bara har 3 metoder:
  • hasNext()- returnerar sant eller falskt, beroende på om det finns ett nästa objekt i listan, eller om vi redan har nått det sista.
  • next()- returnerar nästa objekt i listan
  • remove()- tar bort ett objekt från listan
Som du kan se är iteratorn skräddarsydd för våra behov, och samtidigt är det inget komplicerat med det. Anta att vi vill kontrollera om det finns ett nästa element i vår lista och visa det om det finns:

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
}
Utdata: Cat{name='Thomas'} Cat{name='Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} Som du kan se har den redan implementerat en speciell metod för att skapa ArrayListen iterator: iterator(). Observera dessutom att när vi skapar en iterator anger vi den klass av objekt som den ska fungera med ( ) <Cat>. Summan av kardemumman är att en iterator enkelt hanterar vår ursprungliga uppgift. Ta till exempel bort katten som heter "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);
Utdata: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Du kanske har märkt att vi inte angav vare sig indexet eller namnet i iteratorns remove()metod ! Iteratorn är smartare än den kan se ut: remove()tar bort det sista elementet som returneras av iteratorn. Som du kan se gjorde den precis vad vi ville att den skulle göra :) I princip är detta allt du behöver veta om att ta bort element från en ArrayList. Tja, nästan allt. I nästa lektion ska vi titta in i den här klassen, och se vad som händer där under olika metodanrop :) Tills dess!
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION