CodeGym/Java блог/Случаен/Изтриване на елемент от ArrayList
John Squirrels
Ниво
San Francisco

Изтриване на елемент от ArrayList

Публикувано в групата
здрасти В последния урок се запознахме с ArrayListкласа и научихме How да изпълняваме най-често срещаните операции с този клас. Освен това посочихме няколко разлики между масив ArrayListи обикновен масив. Но ние заобиколихме една тема, а именно How да изтриете елементи от 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 + '\'' +
               '}';
   }
}
Изход: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] Но задаването на елемент от масив на null оставя "дупка". Не сме премахнали позицията в масива, а само съдържанието му. Представете си Howво би се случило, ако имаме масив от 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));
}
Резултат: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] Това изглежда по-добре, но едва ли може да се нарече стабилно решение. Ако не за друго, то поради факта, че трябва да пишем този code всеки път, когато изтриваме елемент от масив! Това е лош вариант. Можем да отидем по друг начин и да създадем отделен метод:
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());
}
Предаваме индекса на нашия обект на метода, който го изтрива (точно Howто в масив). Методът remove()има две особености. Първо, не оставя "дупки". Той вече прилага логиката, необходима за изместване на елементи, когато даден елемент е премахнат от средата, което преди това написахме сами. Вижте изхода от предишния code:
[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='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] Това може да бъде много удобно, ако не искате винаги да следите индекса на желания обект. Изглежда, че разбрахме обикновеното изтриване. Сега нека си представим тази ситуация: искаме да преминем през нашия списък и да премахнем котка с конкретно име . За да направим това, ще използваме бърз 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);
}
Кодът изглежда напълно логичен. Но резултатът може да бъде голяма изненада: Изключение в нишката "main" java.util.ConcurrentModificationException в java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) в java.util.ArrayList$Itr.next(ArrayList. java:831) в Cat.main(Cat.java:25) Има няHowъв вид грешка и не е ясно защо е възникнала. Този процес включва редица нюанси, които трябва да бъдат разгледани. Ето общото правило, което трябва да запомните: Не можете едновременно да преглеждате колекция и да променяте нейните елементи. И имаме предвид всяHowъв вид промяна, не просто премахване. Ако замените премахването на котка с опит за вмъкване на нови котки, резултатът ще бъде същият:
for (Cat cat: cats) {

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

System.out.println(cats);
Изключение в нишката "main" 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 . Това се случва точно когато се опитаме да нарушим правилото по-горе, като променим списъка, докато го обикаляме. В Java се нуждаем от специален обект, наречен итератор (Iteratorклас), за да изтриваме елементи, докато итерираме върху колекция. КласътIteratorе отговорен за безопасното повторение на списъка с елементи. Това е доста просто, тъй като има само 3 метода:
  • hasNext()- връща true or false в зависимост от това дали има следващ елемент в списъка or вече сме стигнали до последния.
  • next()- връща следващия елемент в списъка
  • remove()- премахва елемент от списъка
Както можете да видите, итераторът е напequals специално за нашите нужди и в същото време няма нищо сложно в него. Да предположим, че искаме да проверим дали има следващ елемент в нашия списък и да го покажем, ако има:
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
}
Резултат: Cat{name='Thomas'} Cat{name='Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} Както можете да видите, вече е внедрил специален 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'}] Може би сте забелязали, че не сме посочor нито индекса, нито името в remove()метода на итератора ! Итераторът е по-умен, отколкото може да изглежда: remove()премахва последния елемент, върнат от итератора. Както можете да видите, той направи точно това, което искахме :) По принцип това е всичко, което трябва да знаете за премахването на елементи от ArrayList. Е, почти всичко. В следващия урок ще погледнем вътре в този клас и ще видим Howво се случва там по време на различни извиквания на методи :) Дотогава!
Коментари
  • Популярен
  • Нов
  • Стар
Трябва да сте влезли, за да оставите коментар
Тази страница все още няма коментари