Salom! Oxirgi ma'ruzada biz ArrayList sinfi bilan tanishdik , shuningdek, u bilan eng keng tarqalgan amallarni bajarishni o'rgandik. Bundan tashqari, biz ArrayList va oddiy massiv o'rtasidagi bir nechta farqlarni ta'kidladik. Endi ArrayList dan elementni olib tashlashni ko'rib chiqamiz. Biz allaqachon oddiy massivdagi elementlarni o'chirish juda qulay emasligini aytdik. Hujayraning o'zini o'chira olmasligimiz uchun uning qiymatini faqat "nol" qilishimiz mumkin:
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 + '\'' +
'}';
}
}
Xulosa:
[Cat{name='Томас'}, null, Cat{name='Фorпп Маркович'}]
Ammo qayta o'rnatilganda, massivda "teshik" qoladi. Biz hujayrani o'chirmaymiz, faqat uning tarkibini o'chiramiz. Agar bizda 50 ta mushuk bo'lsa, nima bo'lishini tasavvur qiling, ulardan 17 tasini shu tarzda o'chirib tashladik. Bizda 17 ta teshikli massiv bo'ladi va ularga g'amxo'rlik qiling! Yangi qiymatlarni yozishingiz mumkin bo'lgan bo'sh hujayralar sonini yoddan eslab qolish haqiqiy emas. Bir marta xatoga yo'l qo'ying va siz ob'ektga kerakli havola bilan katakchani qayta yozasiz. Albatta, buni biroz ehtiyotkorlik bilan qilish imkoniyati mavjud: o'chirib tashlaganingizdan so'ng, "teshik" oxirida bo'lishi uchun massivning elementlarini boshiga o'tkazing:
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));
}
Xulosa:
[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}, null]
Endi u yaxshiroq ko'rinadi, ammo buni barqaror yechim deb atash qiyin. Hech bo'lmaganda, chunki har safar massivdan elementni olib tashlaganimizda ushbu kodni qo'lda yozishimiz kerak bo'ladi! Yomon variant. Siz boshqa yo'l bilan borishingiz va alohida usul yaratishingiz mumkin:
public void deleteCat(Cat[] cats, int indexToDelete) {
//...remove the cat by index and shift the elements
}
Ammo bu ham kam foyda keltiradi: bu usul faqat ob'ektlar bilan ishlaydi Cat
, lekin boshqalar bilan ishlay olmaydi. Ya'ni, agar biz massivlardan foydalanmoqchi bo'lgan dasturda yana 100 ta sinf mavjud bo'lsa, ularning har birida aynan bir xil mantiq bilan bir xil usulni yozishimiz kerak bo'ladi. Bu to'liq muvaffaqiyatsizlik -_- Lekin ArrayList sinfida bu muammo muvaffaqiyatli hal qilingan! U elementlarni olib tashlashning maxsus usulini qo'llaydi - 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());
}
Biz ob'ektimiz indeksini metodga o'tkazdik va u o'chirildi (xuddi massivdagi kabi). Usul remove()
ikkita xususiyatga ega. Birinchidan , u "teshiklar" qoldirmaydi. U biz ilgari qo'lda yozgan elementni o'rtadan olib tashlashda elementlarni almashtirish mantiqini allaqachon amalga oshiradi . Konsolda oldingi kodning chiqishiga qarang:
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
Biz bitta mushukni o'rtadan olib tashladik, qolganlari esa bo'shliqlar bo'lmasligi uchun harakatlantirildi. Ikkinchidan , u ob'ektni nafaqat indeks bo'yicha (odatiy massiv kabi), balki ob'ektga havola orqali ham o'chirishi mumkin :
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());
}
Xulosa:
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
Agar siz istalgan ob'ektning indeksini doimo boshingizda saqlashni istamasangiz, bu juda qulay bo'lishi mumkin. Biz odatdagi o'chirishni tartibga soldik. Keling, ushbu vaziyatni tasavvur qilaylik: biz elementlar ro'yxatini takrorlashni va ma'lum bir ismli mushukni olib tashlashni xohlaymiz. Buning uchun biz maxsus sikl operatoridan foydalanamiz for
- for each
. Ushbu ma'ruzada bu haqda ko'proq ma'lumot olishingiz mumkin .
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);
}
Kod juda mantiqiy ko'rinadi. Biroq, natija sizni hayratda qoldirishi mumkin:
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)
Qandaydir xato va nima uchun u to'satdan paydo bo'lganligi noma'lum. Ushbu jarayonda hal qilinishi kerak bo'lgan bir qator nuanslar mavjud. Eslab qolishingiz kerak bo'lgan umumiy qoida: siz bir vaqtning o'zida to'plamni takrorlay olmaysiz va uning elementlarini o'zgartira olmaysiz. Ha, ha, aynan o'zgarish va shunchaki o'chirish emas. Agar siz bizning kodimizda mushuklarni olib tashlashni yangilarini kiritish bilan almashtirishga harakat qilsangiz, natija bir xil bo'ladi:
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)
Biz bir operatsiyani boshqasiga o'zgartirdik, ammo natija o'zgarmadi: bir xil xato ConcurrentModificationException
. Bu biz qoidani buzishga va uni takrorlash paytida ro'yxatni o'zgartirishga harakat qilganimizda sodir bo'ladi. Java-da, iteratsiya paytida elementlarni olib tashlash uchun siz maxsus ob'ektdan - iteratordan (sinf Iterator
) foydalanishingiz kerak. Sinf Iterator
elementlar ro'yxati bo'ylab xavfsiz yurish uchun javobgardir. Bu juda oddiy, chunki u faqat 3 ta usulga ega:
hasNext()
- ro'yxatda keyingi element bor-yo'qligiga yoki oxirgisiga yetib bo'lganimizga qarabtrue
qaytaradi .false
next()
- ro'yxatning keyingi elementini qaytaradiremove()
- elementni ro'yxatdan o'chiradi
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
}
Xulosa:
Cat{name='Томас'}
Cat{name='Бегемот'}
Cat{name='Фorпп Маркович'}
Cat{name='Пушок'}
Ko'rib turganingizdek, sinf ArrayList
allaqachon iterator yaratish uchun maxsus usulni amalga oshiradi - iterator()
. Shuni ham yodda tutingki, iterator yaratishda biz u ishlaydigan ob'ektlar sinfini belgilaymiz ( <Cat>
). Oxir oqibat, biz iterator yordamida asl muammomizni osongina hal qilishimiz mumkin. Masalan, "Filip Markovich" ismli mushukni o'chirib tashlaylik:
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);
Xulosa:
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
Biz iterator usulida element indeksini ham, mos yozuvlar o'zgaruvchisi nomini ham ko'rsatmaganimizni payqagandirsiz remove()
! Iterator tuyulishi mumkin bo'lgandan ko'ra aqlliroq: usul remove()
iterator tomonidan qaytarilgan oxirgi elementni olib tashlaydi. Ko'rib turganingizdek, u kerakli darajada ishladi :) dan elementlarni olib tashlash haqida bilishingiz kerak bo'lgan hamma narsa ArrayList
. Aniqrog'i - deyarli hamma narsa. Keyingi ma'ruzada biz ushbu sinfning "ichki qismi" ni ko'rib chiqamiz va operatsiyalar paytida u erda nima sodir bo'lishini ko'ramiz :) Ko'rishguncha!
GO TO FULL VERSION