pertanyaan
Saya perlu menghapus elemen yang tidak ditentukan dari koleksi pertama dari koleksi java, berdasarkan konten koleksi lain. Ini terlihat sangat sederhana, tapi ini masalah.
Ini adalah kepala metode yang ingin saya tulis
private void screenblacknamelist (daftar <sharedboardsmswrapper> Sumber, Daftar <BacknamelistModel> BlackNamelist)
Beginilah hal -hal. Koleksi sumber menyimpan beberapa elemen data tampilan. Koleksi Blacknamelist menyimpan daftar daftar hitam. Kita perlu menghapus data pengguna daftar hitam di koleksi sumber berdasarkan tabel daftar hitam.
Solusi untuk masalah ini tampaknya sangat sederhana.
Saya pertama kali menggunakan untuk setiap pernyataan untuk menghapus.
untuk (sharedboardsmswrapper tmpsharedboardsmswrapper: source) {for (blacknamelistmodel tmpBlackNamelistModel: blacknamelist) {if (tmpsharedboardsmswrapper.getsource (). Source.remove (tmpsharedboardsmswrapper); merusak; }}}Pertanyaan yang sangat sederhana! Saya tertawa diam -diam,
tes…
Yang mengejutkan saya adalah bahwa kode ini benar -benar melemparkan pengecualian
java.util.ConcurrentModificationException。
Lihat manual JDK6
Public Class ConcurrentModificationExceptionextends runimeException
Pengecualian ini dilemparkan ketika metode mendeteksi modifikasi bersamaan dari objek tetapi tidak mengizinkan modifikasi tersebut.
Misalnya, ketika utas berulang pada koleksi , koleksi lain tidak diizinkan untuk dimodifikasi secara linear. Biasanya dalam kasus ini, hasil iterasi tidak pasti. Jika perilaku ini terdeteksi, beberapa implementasi iterator (termasuk semua implementasi koleksi umum yang disediakan oleh JRE) dapat memilih untuk melempar pengecualian ini. Iterator yang melakukan operasi ini disebut iterator kegagalan cepat karena iterator gagal dengan sangat cepat tanpa mempertaruhkan risiko perilaku tidak pasti sewenang -wenang di suatu waktu di masa depan.
Perhatikan bahwa pengecualian ini tidak selalu menunjukkan bahwa objek telah dimodifikasi secara bersamaan oleh utas yang berbeda. Jika satu utas mengeluarkan urutan metode panggilan yang melanggar kontrak objek, objek dapat melemparkan pengecualian ini. Misalnya, jika utas secara langsung memodifikasi koleksi saat mengulangi koleksi menggunakan iterator gagal cepat, iterator akan melempar pengecualian ini.
Perhatikan bahwa perilaku kegagalan cepat dari iterator tidak dapat dijamin, karena secara umum, tidak mungkin untuk membuat jaminan sulit tentang apakah ada modifikasi bersamaan yang tidak sinkron. Operasi kegagalan cepat akan melakukan yang terbaik untuk melempar ConcurrentModificationException . Oleh karena itu, adalah salah untuk menulis program yang tergantung pada pengecualian ini untuk meningkatkan kebenaran operasi tersebut. Cara yang benar adalah : ConcurrentModificationException harus digunakan hanya untuk mendeteksi bug.
For each di Java benar -benar menggunakan Iterator untuk diproses. Iterator tidak mengizinkan koleksi dihapus selama penggunaan iterator . Dan ketika saya berada di for each , saya menghapus elemen dari koleksi, yang menyebabkan iterator melempar ConcurrentModificationException .
Tampaknya kita hanya bisa menggunakan loop tradisional dengan jujur!
untuk (int i = 0; i <source.size (); i ++) {sharedboardsmswrapper tmpsharedboardsmswrapper = source.get (i); untuk (int j = 0; j <blacknamelist.size (); j ++) {blacknamelistModel tmpBlackNamelistModel = blacknamelist.get (j); if (tmpsharedboardsmswrapper.getSource (). Equals (tmpBlackNamelistModel.getSource ())) {source.remove (tmpsharedboardsmswrapper); merusak; }}}Seharusnya baik -baik saja sekarang! Tekan tes dengan percaya diri ...
pingsan! Apa yang terjadi? Bagaimana data dapat disaring salah?
Setelah pelacakan debug , ditemukan bahwa ketika set menghapus elemen, ukuran set akan menjadi lebih kecil dan indeks akan berubah!
Apa yang harus saya lakukan? Saya tidak akan tidak berdaya dengan masalah sekecil itu!
Gunakan iterator untuk menghapus elemen dalam koleksi
Periksa antarmuka iterator dari manual JDK dan lihat juga memiliki metode hapus .
Menghapus
void rape ()
Lepaskan elemen terakhir yang dikembalikan oleh iterator dari koleksi yang ditunjukkan oleh iterator (operasi opsional). Metode ini hanya dapat dipanggil sekali per panggilan berikutnya. Jika iterator dimodifikasi oleh koleksi yang ditunjuk oleh iterator menggunakan metode selain memanggil metode ini, perilaku iterator tidak pasti.
Melemparkan:
UnsupportedOperationException - Jika iterator tidak mendukung operasi lepas .
IllegalStateException - Jika metode berikutnya belum dipanggil, atau metode hapus telah dipanggil setelah panggilan terakhir ke metode berikutnya .
Kode akhir yang benar:
/ ** *@paramSource *@PARAMBLACKNAMElist */ privatevoid screenblacknamelist (daftar <sharedboardsmswrapper> Sumber, Daftar <Meng <BlacknamelistModel> BlackNamelist) {iterator <SharedBoardsMswrapper> sourceIt = Source.iterator (); while (sourceIt.hasnext ()) {sharedboardsmswrapper tmpsharedboardsmswrapper = sourceit.next (); Iterator <BacknamelistModel> blacknamelistit = blacknamelist.iterator (); while (blacknamelistit.hasnext ()) {blacknamelistModel tmpBlackNamElistModel = blacknamelistit.next (); if (tmpsharedboardsmswrapper.getSource (). equals (tmpBlackNamelistModel.getSource ())) {sourceIt.remove (); merusak; }}}}} Perhatikan bahwa remove() iterator next() tidak dapat dipanggil beberapa kali. Kalau tidak, pengecualian akan dilemparkan.
Tampaknya cara termudah untuk menghapus elemen dalam koleksi adalah dengan menggunakan metode iterator remove() !
Mari kita lihat bagaimana iterator yang disediakan oleh kelas ArrayList diimplementasikan.
PrivateClass ITR mengimplementasikan iterator <E> { /** Ini adalah indeks elemen, yang setara dengan pointer, atau kursor, yang menggunakannya untuk mengakses elemen data daftar. *IndexOfElementToberEturnedBySubequentCallTonext. */ intcursor = 0; /** *IndexOfElementReturnedByMoStrecentCallTonextor *Sebelumnya. Resetto -1iftheSelementIsdeletedbyacall *toremove. 最新元素的索引。 Jika elemen telah dihapus, diatur ke -1 */ intlastret = -1; /** Properti dari ArrayList kelas eksternal: transien yang dilindungi int modcount = 0; Ini digunakan untuk mengamati apakah arraylist sedang dimodifikasi oleh utas lain secara bersamaan. Jika tidak konsisten, pengecualian sinkron akan dilemparkan. *ThemodCountValueThattheIteratorBelievestAntheBacking *listShouldhave. Jika ekspektasi iniviolasi, Theiterator *HasDetectectedCurrentModification. */intexpectedModCount = modcount; // Jika kursor tidak mencapai ukuran daftar, maka masih ada elemen. publicBoolean hasnext () {returnCursor! = size (); } // Kembalikan elemen saat ini dan kemudian kursor +1. Indeks terbaru = indeks elemen yang dikembalikan. publik e next () {checkForComodification (); coba {e next = get (kursor); lastret = kursor ++; kembali berikutnya; } catch (indexOutofboundsException e) {checkForComodification (); melempar nosuchelementException (); }}/*Hapus elemen, yang berarti menghapus elemen saat ini dan menempatkan kursor-1. Karena, daftar akan memindahkan semua elemen berikut ke yang sebelumnya. */ publicVoid remeCE () {if (lastret == -1) Melempar IllegalStateException (); checkForComodification (); coba {abstractlist.this.remove (lastret); if (lastret <kursor) kursor--; lastret = -1; diharapkan modcount = modcount; } catch (IndexOutOfBoundsException e) {Thrownew ConcurrentModificationException (); }} finalVoid checkForComodification () {if (modcount! = diharapkan MODCount) lempar concurrentModificationException (); }}Meringkaskan
Seperti yang Anda lihat, Iterator menghapus elemen dan mengatur ulang kursor ke kursi yang benar. Selama tidak ada utas lain yang mengubah set pada saat yang sama, tidak akan ada masalah. Di atas adalah semua tentang artikel ini, saya harap ini akan membantu semua orang untuk belajar Java.