Saya memiliki ArrayList yang ingin saya ulangi. Sementara iterasi di atasnya saya harus menghapus elemen pada saat bersamaan. Jelas ini melempar a java.util.ConcurrentModificationException
.
Apa praktik terbaik untuk menangani masalah ini? Haruskah saya mengkloning daftar terlebih dahulu?
Saya menghapus elemen tidak di dalam loop itu sendiri tetapi bagian lain dari kode.
Kode saya terlihat seperti ini:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething
mungkin memanggil Test.removeA()
;
Jawaban:
Dua pilihan:
originalList.removeAll(valuesToRemove)
di akhirremove()
metode pada iterator itu sendiri. Perhatikan bahwa ini berarti Anda tidak dapat menggunakan loop yang disempurnakan untuk.Sebagai contoh dari opsi kedua, menghapus string apa pun dengan panjang lebih dari 5 dari daftar:
sumber
Dari JavaDocs di ArrayList
sumber
Anda mencoba untuk menghapus nilai dari daftar dalam lanjutan "untuk loop", yang tidak mungkin, bahkan jika Anda menerapkan trik apa pun (yang Anda lakukan dalam kode Anda). Cara yang lebih baik adalah dengan kode tingkat iterator seperti yang disarankan di sini.
Saya bertanya-tanya bagaimana orang belum menyarankan pendekatan loop tradisional.
Ini juga berfungsi.
sumber
Anda harus benar-benar hanya mengulangi kembali array dengan cara tradisional
Setiap kali Anda menghapus elemen dari daftar, elemen sesudahnya akan didorong maju. Selama Anda tidak mengubah elemen selain yang iterasi, kode berikut ini akan berfungsi.
sumber
Di Java 8 Anda bisa menggunakan Collection Interface dan melakukan ini dengan memanggil metode removeIf:
Informasi lebih lanjut dapat ditemukan di sini
sumber
Lakukan perulangan dengan cara biasa,
java.util.ConcurrentModificationException
yaitu kesalahan yang berhubungan dengan elemen yang diakses.Jadi cobalah:
sumber
java.util.ConcurrentModificationException
dengan tidak menghapus apa pun dari daftar. Rumit. :) Anda tidak dapat benar-benar menyebut ini "cara biasa" untuk mengulang daftar.Saat iterasi daftar, jika Anda ingin menghapus elemen dimungkinkan. Coba lihat di bawah ini contoh saya,
Saya memiliki nama-nama daftar Array di atas. Dan saya ingin menghapus nama "def" dari daftar di atas,
Kode di atas melempar pengecualian ConcurrentModificationException karena Anda memodifikasi daftar saat iterasi.
Jadi, untuk menghapus nama "def" dari Arraylist dengan melakukan cara ini,
Kode di atas, melalui iterator kita dapat menghapus "def" nama dari Arraylist dan mencoba untuk mencetak array, Anda akan melihat output di bawah ini.
Output: [abc, ghi, xyz]
sumber
Salah satu opsi adalah memodifikasi
removeA
metode ini -Tetapi ini berarti Anda
doSomething()
harus dapat lulusiterator
keremove
metode. Bukan ide yang sangat bagus.Dapatkah Anda melakukan ini dalam pendekatan dua langkah: Pada loop pertama ketika Anda mengulangi daftar, alih-alih menghapus elemen yang dipilih, tandai mereka sebagai yang akan dihapus . Untuk ini, Anda cukup menyalin elemen-elemen ini (salinan dangkal) ke yang lain
List
.Kemudian, setelah iterasi Anda selesai, cukup lakukan
removeAll
dari daftar pertama semua elemen dalam daftar kedua.sumber
Berikut adalah contoh di mana saya menggunakan daftar yang berbeda untuk menambahkan objek untuk dihapus, kemudian setelah itu saya menggunakan stream.foreach untuk menghapus elemen dari daftar asli:
sumber
Alih-alih menggunakan Untuk setiap loop, gunakan normal untuk loop. misalnya, kode di bawah ini menghapus semua elemen dalam daftar array tanpa memberikan java.util.ConcurrentModificationException. Anda dapat memodifikasi kondisi dalam loop sesuai dengan kasus penggunaan Anda.
sumber
Lakukan beberapa cara sederhana seperti ini:
sumber
Solusi Java 8 alternatif menggunakan stream:
Di Java 7 Anda bisa menggunakan Jambu biji sebagai gantinya:
Perhatikan, bahwa contoh Guava menghasilkan daftar yang tidak berubah yang mungkin atau mungkin tidak seperti yang Anda inginkan.
sumber
Anda juga dapat menggunakan CopyOnWriteArrayList sebagai ganti ArrayList. Ini adalah pendekatan yang direkomendasikan terbaru oleh dari JDK 1.5 dan seterusnya.
sumber
Dalam kasus saya, jawaban yang diterima tidak berfungsi, ini menghentikan Pengecualian tetapi menyebabkan beberapa inkonsistensi dalam Daftar saya. Solusi berikut ini sangat cocok untuk saya.
Dalam kode ini, saya telah menambahkan item untuk dihapus, dalam daftar lain dan kemudian menggunakan
list.removeAll
metode untuk menghapus semua item yang diperlukan.sumber
"Haruskah aku mengkloning daftar itu dulu?"
Itu akan menjadi solusi termudah, hapus dari klon, dan salin kembali klon setelah dihapus.
Contoh dari game rummikub saya:
sumber
stones = (...) clone.clone();
berlebihan. Tidak akanstones = clone;
melakukan hal yang sama?stones
. Dengan cara ini Anda bahkan tidak perluclone
variabel:for (Stone stone : (ArrayList<Stone>) stones.clone()) {...
Jika tujuan Anda adalah untuk menghapus semua elemen dari daftar, Anda dapat mengulangi setiap item, dan kemudian menelepon:
sumber
Saya datang terlambat, saya tahu tetapi saya menjawab ini karena saya pikir solusi ini sederhana dan elegan:
Semua ini untuk memperbarui dari satu daftar ke yang lain dan Anda dapat membuat semuanya hanya dari satu daftar dan dalam metode memperbarui Anda memeriksa kedua daftar dan dapat menghapus atau menambahkan elemen di antara daftar. Ini berarti kedua daftar selalu berukuran sama
sumber
Gunakan Iterator sebagai ganti Array List
Apakah set dikonversi ke iterator dengan jenis yang cocok
Dan pindah ke elemen selanjutnya dan hapus
Pindah ke yang berikutnya penting di sini karena harus mengambil indeks untuk menghapus elemen.
sumber
Bagaimana dengan
sumber
Tambahkan saja break setelah pernyataan ArrayList.remove (A) Anda
sumber