java 集合体系

2018-08-29  本文已影响4人  最美下雨天

图片来源: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值

上一篇 下一篇

猜你喜欢

热点阅读