java 集合体系

图片来源:https://blog.csdn.net/csp277/article/details/46462605

image.png

Collection继承了Iterable接口

关于集合遍历时增删元素:
这样可以

Iterator<String> iterator=list.iterator();
                while(iterator.hasNext())
                {
                    if(iterator.next().equals("bbb"))
                    {
                        iterator.remove();
                    }

                }

普通for循环也可以

for(int i=0;i<list.size();i++)
                {
                    if(list.get(i).equals("bbb"))
                    {
                        list.remove(i);
                    }
                }

但是增强for循环是不可以的

for(String str:list)
                {
                    if(str.equals("bbb"))
                    {
                        list.remove(str);
                    }
                }

会抛出java.util.ConcurrentModificationException异常
利用迭代器进行迭代时,直接用list删除元素也是不可以的

 Iterator<String> iterator=list.iterator();
                while(iterator.hasNext())
                {
                    String next=iterator.next();
                    if(next.equals("bbb"))
                    {
                        list.remove(next);
                    }

                }

会抛出java.util.ConcurrentModificationException异常


image.png

看异常的日志,是在调用next()方法的时候才抛出的,并非调用list.remove()的时候
为什么抛出了异常,看下ArrayList中的代码:


image.png

image.png

在next()方法的第一句就做了判断
我们调用list.iterator()的时候会初始化Itr

public Iterator<E> iterator() {
        return new Itr();
    }
image.png

初始化时便会对expectedModCount进行赋值,既然next()方法中抛出了异常,说明两个值不等了,那必然是list.remove()方法对modCount进行了修改,看下list.remove()方法


image.png

modCount的值修改了,但是Itr的成员变量expectedModCount的值并没有发生变化,所以这儿抛出了异常。

那么java为什么要这么设计呢,如果不抛出这个异常,继续让程序往下面走,会发生什么情况?

利用迭代器在遍历集合的过程中是利用cursor这个变量控制的

 int cursor;       // index of next element to return

在迭代过程中会利用it.hasNext()来判断是否还有下一个元素

        protected int limit = ArrayList.this.size;

        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor < limit;
        }

其实这个操作并没有什么影响,这儿是可以正确拿到集合的大小的,但是你会发现在next()遍历中会存在跳过元素的情况


image.png

假设遍历到集合的第二个元素时,删除了第二个元素,但是此时cursor是等于2


image.png

再调用next的时候原先的第三个元素变为了第二个元素,cursor没有做任何操作,值为2,此时就跳过了第二个元素,直接遍历第三个元素了,这就不正常了。

那么调用iterator.remove()方法为什么可以呢?
image.png

因为在这个方法中会同步更新cursor值

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容