JavaRush /Java блогы /Random-KK /Java тіліндегі ArrayList тізімінен элементті жою

Java тіліндегі ArrayList тізімінен элементті жою

Топта жарияланған
Сәлеметсіз бе! Соңғы дәрісте біз 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("Hippopotamus");
       cats[2] = new Cat("Philip Markovich");

       cats[1] = null;

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


@Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
Қорытынды:

[Cat{name='Томас'}, null, Cat{name='Фorпп Маркович'}]
Бірақ қалпына келтіру кезінде массивте «тесік» қалады. Біз ұяшықты жоймаймыз, тек оның мазмұны. Егер бізде 50 мысық массиві болса, не болатынын елестетіп көріңіз, оның 17-сін осылай жойдық. Бізде 17 тесігі бар массив болады және оларға қамқорлық жасаңыз! Жаңа мәндерді жазуға болатын бос ұяшықтардың санын жатқа есте сақтау шындыққа жанаспайды. Бір рет қате жіберіңіз, сонда сіз нысанға қажетті сілтемесі бар ұяшықты қайта жазасыз. Әрине, мұны сәл мұқият орындауға мүмкіндік бар: жойғаннан кейін «тесік» соңында болатындай массив элементтерін басына жылжытыңыз:
public static void main(String[] args) {

   Cat[] cats = new Cat[4];
   cats[0] = new Cat("Thomas");
   cats[1] = new Cat("Hippopotamus");
   cats[2] = new Cat("Philip Markovich");
   cats[3] = new Cat("Fluff");

   cats[1] = null;

   for (int i = 2; i < cats.length-1; i++) {
       //move the elements to the beginning so that the empty cell is at the end
       cats[i-1] = cats[i];
       cats[i] = null;
   }

   System.out.println(Arrays.toString(cats));
}
Қорытынды:

[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}, null]
Енді бұл жақсырақ көрінеді, бірақ мұны тұрақты шешім деп атауға болмайды. Кем дегенде, өйткені біз массивтен элементті жойған сайын бұл codeты қолмен жазуымыз керек! Нашар опция. Сіз басқа жолмен жүріп, бөлек әдіс жасай аласыз:
public void deleteCat(Cat[] cats, int indexToDelete) {
   //...remove the cat by index and shift 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("Hippopotamus");
   Cat philipp = new Cat("Philip Markovich");
   Cat pushok = new Cat("Fluff");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);
   System.out.println(cats.toString());

   cats.remove(1);

   System.out.println(cats.toString());
}
Біз нысанның индексін әдіске бердік және ол жойылды (массивтегі сияқты). Әдістің remove()екі қасиеті бар. Біріншіден , ол «тесіктерді» қалдырмайды. Ол біз бұрын қолмен жазған ортасынан элементті алып тастау кезінде элементтерді ауыстыру логикасын жүзеге асырады . Консольдегі алдыңғы codeтың шығысын қараңыз:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
Бір мысықты ортасынан алып тастадық, ал қалғандарын саңылау болмас үшін айналдырдық. Екіншіден , ол нысанды индекс бойынша ғана емес (тұрақты массив сияқты), сонымен қатар нысанға сілтеме арқылы да жоя алады :
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Hippopotamus");
   Cat philipp = new Cat("Philip Markovich");
   Cat pushok = new Cat("Fluff");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);
   System.out.println(cats.toString());

   cats.remove(philipp);

   System.out.println(cats.toString());
}
Қорытынды:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
Қажетті нысанның индексін әрқашан басыңызда сақтағыңыз келмесе, бұл өте ыңғайлы болуы мүмкін. Біз әдеттегі жоюды ретке келтірген сияқтымыз. Енді мына жағдайды елестетіп көрейік: біз элементтер тізімін қайталап, белгілі бір атаумен мысықты алып тастағымыз келеді. Ол үшін арнайы цикл операторын қолданамыз for- for each. Бұл туралы толығырақ осы лекциядан біле аласыз .
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Hippopotamus");
   Cat philipp = new Cat("Philip Markovich");
   Cat pushok = new Cat("Fluff");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);

   for (Cat cat: cats) {

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

   System.out.println(cats);
}
Код өте қисынды болып көрінеді. Дегенмен, нәтиже сізді таң қалдыруы мүмкін:

Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
  at java.util.ArrayList$Itr.next(ArrayList.java:831)
  at Cat.main(Cat.java:25)
Қандай да бір қателік және оның неге кенеттен пайда болғаны белгісіз. Бұл процесте шешуді қажет ететін бірқатар нюанстар бар. Есте сақтау керек жалпы ереже: Сіз бір уақытта жиынды қайталай алмайсыз және оның элементтерін өзгерте алмайсыз. Иә, иә, дәл өзгерту, жай ғана жою емес. Егер сіз біздің codeымызда мысықтарды алып тастауды жаңаларын енгізуге ауыстыруға тырыссаңыз, нәтиже бірдей болады:
for (Cat cat: cats) {

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

System.out.println(cats);

Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
  at java.util.ArrayList$Itr.next(ArrayList.java:831)
  at Cat.main(Cat.java:25)
Біз бір операцияны екіншісіне ауыстырдық, бірақ нәтиже өзгермеді: бірдей қате ConcurrentModificationException. Бұл ережені бұзуға және оны қайталау кезінде тізімді өзгертуге тырысқанда дәл орын алады. Java тілінде итерация кезінде элементтерді жою үшін арнайы нысанды - итераторды (класс ) пайдалану керек Iterator. Сынып Iteratorэлементтер тізімі бойынша қауіпсіз жүруге жауапты. Бұл өте қарапайым, өйткені оның тек 3 әдісі бар:
  • hasNext()- тізімде келесі элементтің бар-жоғына немесе соңғысына жеткенімізге байланысты trueқайтарады .false
  • 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 next element
   System.out.println(nextCat);// print it to the console
}
Қорытынды:

Cat{name='Томас'}
Cat{name='Бегемот'}
Cat{name='Фorпп Маркович'}
Cat{name='Пушок'}
Көріп отырғаныңыздай, сынып ArrayListитераторды жасаудың арнайы әдісін іске асырып қойған iterator(). Сондай-ақ, итераторды жасау кезінде біз оның жұмыс істейтін an objectілер класын көрсететінін ескеріңіз ( <Cat>). Сайып келгенде, біз итератордың көмегімен бастапқы мәселемізді оңай шеше аламыз. Мысалы, «Фorп Маркович» атты мысықты жойайық:
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 next element
   if (nextCat.name.equals("Philip Markovich")) {
       catIterator.remove();//delete the cat with the desired name
   }
}

System.out.println(cats);
Қорытынды:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
Итератор әдісінде элемент индексін де, анықтамалық айнымалы атауын да көрсетпегенімізді байқаған боларсыз remove()! Итератор көрінгеннен ақылдырақ: әдіс remove()итератор қайтарған соңғы элементті жояды. Көріп отырғаныңыздай, ол дәл қажетінше жұмыс істеді :) Бұл негізінен элементтерді жою туралы білуіңіз керек нәрсенің бәрі ArrayList. Дәлірек айтқанда - барлығы дерлік. Келесі дәрісте біз осы сыныптың «ішкі жағын» қарастырамыз және онда операциялар кезінде не болатынын көреміз :) Кездескенше!
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION