JavaRush /Blog Java /Random-MS /Mengalih keluar elemen daripada ArrayList dalam Java

Mengalih keluar elemen daripada ArrayList dalam Java

Diterbitkan dalam kumpulan
hello! Dalam kuliah terakhir, kami berkenalan dengan kelas ArrayList , dan juga belajar cara melaksanakan operasi yang paling biasa dengannya. Di samping itu, kami telah menyerlahkan beberapa perbezaan antara ArrayList dan tatasusunan biasa. Sekarang mari kita lihat mengalih keluar elemen daripada ArrayList. Kami telah mengatakan bahawa memadam elemen dalam tatasusunan biasa tidak begitu mudah. Mengalih keluar elemen daripada ArrayList - 1Oleh kerana kita tidak boleh memadamkan sel itu sendiri, kita hanya boleh "sifar" nilainya:
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 + '\'' +
               '}';
   }
}
Kesimpulan:

[Cat{name='Томас'}, null, Cat{name='Фorпп Маркович'}]
Tetapi apabila ditetapkan semula, "lubang" kekal dalam tatasusunan. Kami tidak memadamkan sel, tetapi hanya kandungannya. Bayangkan apa yang akan berlaku jika kita mempunyai susunan 50 kucing, 17 daripadanya kita padamkan dengan cara ini. Kami akan mempunyai tatasusunan dengan 17 lubang, dan menjaganya! Mengingati dengan hati bilangan sel kosong di mana anda boleh menulis nilai baharu adalah tidak realistik. Buat kesilapan sekali dan anda akan menulis ganti sel dengan rujukan yang diingini kepada objek. Sudah tentu, terdapat peluang untuk melakukannya dengan lebih berhati-hati: selepas memadam, gerakkan elemen tatasusunan ke permulaan, supaya "lubang" berada di penghujung:
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));
}
Kesimpulan:

[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}, null]
Sekarang ia kelihatan lebih baik, tetapi ini tidak boleh dipanggil penyelesaian yang stabil. Sekurang-kurangnya, kerana kita perlu menulis kod ini dengan tangan setiap kali kita mengalih keluar elemen daripada tatasusunan! Pilihan yang buruk. Anda boleh pergi dengan cara lain dan membuat kaedah berasingan:
public void deleteCat(Cat[] cats, int indexToDelete) {
   //...remove the cat by index and shift the elements
}
Tetapi ini juga tidak banyak digunakan: kaedah ini hanya boleh berfungsi dengan objek Cat, tetapi tidak boleh berfungsi dengan orang lain. Iaitu, jika terdapat 100 lagi kelas dalam program yang kita mahu gunakan tatasusunan, kita perlu menulis kaedah yang sama dengan logik yang sama dalam setiap satu daripadanya. Ini adalah kegagalan sepenuhnya -_- Tetapi dalam kelas ArrayList masalah ini berjaya diselesaikan! Ia melaksanakan kaedah khas untuk mengalih keluar elemen - 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());
}
Kami lulus indeks objek kami kepada kaedah, dan ia telah dipadamkan (sama seperti dalam tatasusunan). Kaedah ini remove()mempunyai dua ciri. Pertama , ia tidak meninggalkan "lubang". Ia sudah melaksanakan logik peralihan elemen apabila mengeluarkan elemen dari tengah, yang sebelum ini kami tulis dengan tangan. Lihat output kod sebelumnya dalam konsol:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
Kami mengeluarkan seekor kucing dari tengah dan yang lain dialihkan supaya tiada jurang. Kedua , ia boleh memadam objek bukan sahaja dengan indeks (seperti tatasusunan biasa), tetapi juga dengan merujuk kepada objek :
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());
}
Kesimpulan:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Фorпп Маркович'}, Cat{name='Пушок'}]
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
Ini boleh menjadi sangat mudah jika anda tidak mahu sentiasa menyimpan indeks objek yang diingini dalam kepala anda. Kami nampaknya telah menyelesaikan pemadaman biasa. Sekarang mari kita bayangkan keadaan ini: kita mahu melelakan senarai elemen kami dan mengalih keluar kucing dengan nama tertentu. Untuk ini kami menggunakan pengendali gelung khas for- for each. Anda boleh mengetahui lebih lanjut mengenainya dalam kuliah ini .
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 itu kelihatan agak logik. Walau bagaimanapun, hasilnya mungkin mengejutkan anda:

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)
Beberapa jenis ralat, dan tidak jelas mengapa ia muncul secara tiba-tiba. Terdapat beberapa nuansa dalam proses ini yang perlu ditangani. Peraturan am yang perlu anda ingat: Anda tidak boleh melelang melalui koleksi dan menukar elemennya pada masa yang sama. Ya, ya, betul-betul perubahan, dan bukan hanya pemadaman. Jika anda mencuba dalam kod kami untuk menggantikan penyingkiran kucing dengan penyisipan yang baharu, hasilnya akan sama:
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)
Kami menukar satu operasi kepada yang lain, tetapi hasilnya tidak berubah: ralat yang sama ConcurrentModificationException. Ia berlaku dengan tepat apabila kita cuba melanggar peraturan dan menukar senarai semasa mengulanginya. Di Jawa, untuk mengalih keluar elemen semasa lelaran, anda perlu menggunakan objek khas - iterator (class Iterator). Kelas Iteratorbertanggungjawab untuk berjalan dengan selamat melalui senarai elemen. Ia agak mudah kerana ia hanya mempunyai 3 kaedah:
  • hasNext()- kembali truesama ada falsebergantung pada sama ada terdapat elemen seterusnya dalam senarai, atau sama ada kita telah mencapai yang terakhir.
  • next()- mengembalikan elemen senarai seterusnya
  • remove()- mengalih keluar elemen daripada senarai
Seperti yang anda lihat, iterator secara literal "disesuaikan" dengan keperluan kami, dan tidak ada yang rumit mengenainya. Sebagai contoh, kami ingin menyemak sama ada senarai kami mengandungi elemen berikut, dan jika ya, cetaknya ke konsol:
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
}
Kesimpulan:

Cat{name='Томас'}
Cat{name='Бегемот'}
Cat{name='Фorпп Маркович'}
Cat{name='Пушок'}
Seperti yang anda lihat, kelas ArrayListsudah melaksanakan kaedah khas untuk mencipta iterator - iterator(). Juga, ambil perhatian bahawa apabila mencipta iterator, kami menentukan kelas objek yang ia akan berfungsi ( <Cat>). Akhirnya, kami boleh menyelesaikan masalah asal kami dengan mudah menggunakan iterator. Sebagai contoh, mari padamkan kucing bernama "Philip Markovich":
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);
Kesimpulan:

[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='Пушок'}]
Anda mungkin perasan bahawa kami tidak menyatakan sama ada indeks elemen atau nama pembolehubah rujukan dalam kaedah iterator remove()! Peulang adalah lebih bijak daripada yang mungkin kelihatan: kaedah remove()mengalih keluar elemen terakhir yang dikembalikan oleh peulang. Seperti yang anda boleh lihat, ia berfungsi tepat seperti yang diperlukan :) Itulah pada asasnya semua yang anda perlu tahu tentang mengalih keluar elemen daripada ArrayList. Lebih tepat lagi - hampir segala-galanya. Dalam kuliah seterusnya kita akan melihat ke dalam "bahagian dalam" kelas ini dan melihat apa yang berlaku di sana semasa operasi :) Jumpa anda!
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION