集合中的迭代器

这几天学习了集合,今天咱们说一下迭代器这个东西

1.为什么要有迭代器?

我们使用迭代器的用途之一就是遍历集合,然而我们明明可以使用一下这种方法遍历ArrayList,为什么还要用迭代器呢?

public void test(){
        ArrayList<String> list = new ArrayList<>();
        list.add("你好");
        list.add("感谢阅读");
        list.add("我的");
        list.add("文章^_Q");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }     
    }

可是对于ArrayList这种集合这是可行的,而对于Set类型的集合就不可以了,因此Java需要定义通用的方式来操作不同类型集合,而Iterator接口就是来实现这个目的

2.迭代器常用方法

方法 作用
boolean hasNext() 如果仍有元素可以迭代,返回true
E next() 返回迭代的下一个元素
void remove() 从迭代器指向的 Collection 中移除迭代器返回的最后一个元素

3.迭代器遍历怎么运作

这是一段迭代器遍历的代码

public void test(){
        ArrayList<String> list = new ArrayList<>();
        list.add("你好");
        list.add("感谢阅读");
        list.add("我的");
        list.add("文章^_Q");
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

    }

初始情况下,可以认为光标指向第一个元素的上方
集合中的迭代器_第1张图片

通过调用hasNext()方法,判断光标下是否有元素。如果有,调用next()方法,使光标下移,指向0号元素,返回0号元素;如果没有,结束。
那么可以将上述三种方法简单认为是这样(迭代器真正的实现不是这样,但是也就是这个逻辑):

hasNext()方法的作用是判断光标下个位置是不是有元素
next() 方法的作用是将光标下移,返回光标指向的元素
remove() 的作用是 删除光标指向的元素

4.迭代器使用常见的错误

先看两段代码

代码一:
public void test(){
        ArrayList<String> list = new ArrayList<>();
        list.add("你好");
        list.add("感谢阅读");
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String str = it.next();
            if ("你好".equals(str)) list.remove(str);
        }
        System.out.println(list);
    }

//运行结果为:
[感谢阅读]

代码二:
public void test(){
        ArrayList<String> list = new ArrayList<>();
        list.add("你好");
        list.add("感谢阅读");
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String str = it.next();
            if ("感谢阅读".equals(str)) list.remove(str);
        }
        System.out.println(list);
    }
//运行结果为:
java.util.ConcurrentModificationException

为什么?先来看看源码吧
集合中的迭代器_第2张图片
代码一分析:

cursor初始化为0,size为2,两者不等于,所以hasNext()方法返回true,然后调用next方法,i=0,然后两个if不满足,cursor变为1,返回索引为0的元素,str=“你好”,此时代码中equals()返回true,顺利删除了元素"你好",此时集合的size从2就变成了1,再次调用hasNext(),cursor和size的值都为1,返回false,while循环结束,最后打印,很顺利结束。

代码二分析

cursor初始化为0,size为2,两者不等于,所以hasNext()方法返回true,然后调用next方法,i=0,然后两个if不满足,cursor变为1,返回索引为0的元素,str=“你好”,此时代码中equals()返回false,然后再次调用hasNext()方法,此时cursor为1,size为2,返回true,调用next()方法,令i = 1,然后两个if不满足,cursor变为2,返回索引为1的元素,str此时为"感谢阅读",此时代码中equals()返回true,顺利删除了元素"感谢阅读",此时集合的size从2就变成了1,再次调用hasNext(),cursor为2,size为1,两者不等于,所以hasNext()方法返回true,然后调用next方法,然而此时的modCount不等于expectedModCount,抛出异常checkForComodification()
集合中的迭代器_第3张图片

原来这就是出错的原因:集合中有个变量modCount,在集合中记录当前集合被修改的次数,迭代器中有个变量expectedModCount初始的值为ModCount,出现上面的情况是因为调用了集合中的remove方法,使得modCount加1,令modCount不等于expectedModCount,则抛出异常checkForComodification(),程序结束。

总结:

使用迭代器遍历集合时,每当集合内部结构发生变化时,就有可能出错,所以遍历集合时删除特定元素要用迭代器中的remove方法

以下是正确方式

public void test(){
        ArrayList<String> list = new ArrayList<>();
        list.add("你好");
        list.add("感谢阅读");
        list.add("我的");
        list.add("文章^_Q");
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String str = it.next();
            if ("感谢阅读".equals(str)) it.remove();
        }
        System.out.println(list);
    }

你可能感兴趣的:(Java,java)