Rumah  >  Soal Jawab  >  teks badan

为什么java不要在foreach循环里进行元素的remove/add操作


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

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

PHPzPHPz2716 hari yang lalu1130

membalas semua(8)saya akan balas

  • 大家讲道理

    大家讲道理2017-04-18 10:56:42

    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

    balas
    0
  • PHP中文网

    PHP中文网2017-04-18 10:56:42

    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...

    balas
    0
  • 天蓬老师

    天蓬老师2017-04-18 10:56:42

    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 .

    balas
    0
  • 黄舟

    黄舟2017-04-18 10:56:42

    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

    balas
    0
  • PHPz

    PHPz2017-04-18 10:56:42

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

    balas
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-18 10:56:42

    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.

    balas
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:56:42

    Hanya padamkannya dalam susunan terbalik

    balas
    0
  • PHP中文网

    PHP中文网2017-04-18 10:56:42

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

    balas
    0
  • Batalbalas