为什么java不要在foreach循环里进行元素的remove/add操作
PHPz
PHPz 2017-04-18 10:54:42
0
8
1196


选自《阿里巴巴JAVA开发手册》

图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?

PHPz
PHPz

学习是最好的投资!

membalas semua(8)
大家讲道理

Punca ralat checkForComodification() boleh diketahui daripada ralat yang dilaporkan Jika anda ingin mengelakkan ralat, anda perlu mengekalkan modCount != expectedModCount sebagai false .
list.remove(Object) akan memanggil kaedah fastRemove(int), dan ia pasti akan mengubah suai modCount pada masa ini, dan ralat akan berlaku pada masa ini.
Iterator<String> iterator = list.iterator() ; Pelaksanaan kaedah ini adalah untuk mengembalikan kelas dalaman Itr (kelas ini digunakan dalam proses lelaran), tetapi mengapa ini iterator.remove() tidak menyebabkan ralat adalah kerana ia mempunyai sesuatu untuk dilakukan dengan kaedah ini Pelaksanaannya adalah untuk menyemak ArrayList.this.remove sebelum melakukan checkForComodfication sebenar dan membuat remove selepas expectedModCount = modCount supaya tiada ralat berlaku.

Itr.remove Pelaksanaan

public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

Jika ada apa-apa yang salah, sila nyatakan @ChaCha哥 @puliuyinyi

Ty80

Dalam kes urutan tunggal, apabila memadamkan elemen semasa melintasi Senarai, anda mesti menggunakan kaedah alih keluar Iterator dan bukannya kaedah alih keluar Senarai, jika tidak ConcurrentModificationException akan berlaku. Cuba bayangkan jika seorang guru mengira bilangan pelajar dalam keseluruhan kelas, dan jika pelajar tidak mematuhi peraturan dan keluar masuk, pasti guru tidak dapat mengira mereka.

Dalam kes multi-threading, sila rujuk salah satu blog saya: http://xxgblog.com/2016/04/02...

Peter_Zhu

Pertama sekali, ini melibatkan operasi berbilang benang Iterator tidak menyokong operasi berbilang benang Kelas Senarai akan mengekalkan pembolehubah modCount secara dalaman untuk merekodkan bilangan pengubahsuaian
Contoh: kod sumber ArrayList

.
protected transient int modCount = 0;

Setiap kali Iterator dijana, Iterator akan merekodkan modCount Setiap kali kaedah seterusnya() dipanggil, rekod akan dibandingkan dengan modCount bagi Senarai kelas luaran Jika didapati tidak sama, a Pengecualian penyuntingan berbilang benang akan dibuang.

Mengapa anda melakukan ini? Pemahaman saya ialah anda mencipta iterator yang berganding rapat dengan kandungan koleksi yang akan dilalui, yang bermaksud bahawa kandungan koleksi yang sepadan dengan iterator ini adalah kandungan semasa saya pasti tidak mahu melakukannya dalam saya isihan gelembung Apabila , masih ada benang yang memasukkan data ke dalam koleksi saya, bukan? Jadi Java menggunakan mekanisme pemprosesan mudah ini untuk menghalang koleksi daripada diubah suai semasa traversal.

Mengenai mengapa memadamkan "1" sudah cukup, sebabnya terletak pada kaedah hasNext() foreach dan iterator Gula sintaksis foreach sebenarnya

while(itr.hasNext()){
    itr.next()
}

Jadi setiap gelung akan melaksanakan hasNext() dahulu, jadi lihat bagaimana ArrayList hasNext() ditulis:

public boolean hasNext() {
    return cursor != size;
}

kursor ialah pembolehubah yang digunakan untuk menandakan kedudukan iterator Pembolehubah bermula dari 0 dan melakukan operasi +1 setiap kali seterusnya dipanggil, jadi:
Selepas kod anda memadamkan "1", saiz=1, kursor =1, pada masa ini hasNext() mengembalikan false dan menamatkan gelung, jadi iterator anda tidak memanggil di sebelah untuk mencari elemen kedua, jadi tidak ada cara untuk mengesan modCount, jadi tidak akan ada pengecualian pengubahsuaian berbilang benang
tetapi apabila Apabila anda memadamkan "2", iterator memanggil seterusnya dua kali Pada masa ini, saiz=1, kursor=2, dan hasNext() kembali benar, jadi iterator secara bodoh memanggil next() sekali lagi, yang juga mencetuskan If. modCount tidak sama, pengecualian pengubahsuaian berbilang benang akan dilemparkan.

Apabila set anda mempunyai tiga elemen, anda akan mendapati bahawa pemadaman "1" akan membuang pengecualian, tetapi pemadaman "2" tidak akan menjadi masalah Sebabnya adalah berkaitan dengan pelaksanaan program di atas Pesanan adalah konsisten .

黄舟

Oleh kerana nombor dalam koleksi berubah apabila anda menambah atau memadam elemen, masalah mungkin berlaku semasa merentasi Contohnya, jika koleksi mempunyai 10 elemen, ia harus dilalui 10 kali Apabila anda Jika elemen ditambah atau dipadam. bilangan traversal tidak betul, jadi ralat akan dilaporkan

PHPzhong

Hanya padamkannya dalam susunan terbalik Bagaimanapun, cuba untuk tidak mengalih keluar senarai itu. Anda boleh menambah tag padam

伊谢尔伦

Penerangan kuning dalam dokumen sangat menarik.

Hasil pelaksanaan contoh ini akan melebihi jangkaan semua orang Jadi cuba gantikan "1" dengan "2", adakah ia akan mendapat hasil yang sama?

Anda masih perlu melihat kod sumber ArrayList untuk ini, anda akan mengetahuinya sepintas lalu.

巴扎黑

Hanya padamkannya dalam susunan terbalik

Ty80

ArrayList tidak selamat untuk benang, yang bermaksud anda mengubah suai Senarai semasa melintasi.
ArrayList akan membuang pengecualian pengubahsuaian serentak dalam kes ini.

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan