zoukankan      html  css  js  c++  java
  • java 迭代器

    一  概念

    迭代器是一个对象,它的工作是遍历并选择序列中的对象,它提供了一种访问一个容器对象中的各个元素的方法,而不必暴露容器对象的内部细节。

        作用:

        1   通过迭代器,开发人员不需要了解容器结构,就可以遍历容器元素。被称为轻量级容器(创建迭代器代价很小)

        2   它的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常

    二  用法

    Java中的Iterator功能比较简单,并且只能单向移动:

      (1) 使用方法iterator()要求容器返回一个Iterator对象。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。

      (2) 使用next()获得序列中的下一个元素。

      (3) 使用hasNext()检查序列中是否还有元素。

      (4) 使用remove()将迭代器新返回的元素删除。

    简单例子

    import java.util.*;
    public class Muster {
     
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            list.add("a");
            list.add("b");
            list.add("c");
            Iterator it = list.iterator();
            while(it.hasNext()){
                String str = (String) it.next();
                System.out.println(str);
            }
        }
    }
    View Code

    三  迭代器是失效问题(删除或新增元素)

    在创建迭代器之后,除非通过迭代器自身的remove 或add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出ConcurrentModificationException

    public class ArrayListTest {
        public static void main(String args[])
        {
            List<String> strList = new ArrayList<String>();
            //迭代器
            Iterator<String> iterator = strList.iterator();
    
             //修改了集合
            for (int i = 0; i < 10; i++)
            {
                strList.add("string" + i);
            }
            
            while (iterator.hasNext())
            {
                System.out.println(iterator.next());
            }
        }

    运行该段代码,会发现其抛出如下异常:

    Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at com.xyh.collection.ArrayListTest.main(ArrayListTest.java:21)
         原因在于在迭代器创建之后,通过ArrayList自身的add方法对列表进行了修改,导致迭代器失效。当将蓝色创建迭代器的代码移动到while循环的上方后,则不会出现该问题。即创建迭代器后不能再通过容器的add/remove方法来改变容器的数据,否则会导致迭代器的失效。

    包括下面这种写法,也是会导致同样的异常

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
            
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        list.add("f");
        list.add("g");
        list.add("h");
            
        Iterator<String> it = list.iterator();
            
        while (it.hasNext()) {
            String str = it.next();
                
            if (str.equals("f")) {
                list.remove(str);
            }
        }
    }
    View Code

    上面异常的本质是

    remove操作里涉及到的expectedModCount = modCount;  值为调用容器的iterator()方法返回iterator对象时,容器中的元素个数

    在网上查到说这是集合迭代中的一种“快速失败”机制,这种机制提供迭代过程中集合的安全性。

    从源代码里可以看到增删操作都会使modCount++,通过和expectedModCount的对比,迭代器可以快速的知道迭代过程中是否存在list.add()类似的操作,存在的话快速失败!

    而我们也知道,集合元素的删除,不能用foreach  这又是为什么?

    foreach中的remove方法实际上使用list.remove一样会报ConcurrentModificationException异常。因为foreach在jvm中还是会解析成Iterator来执行的,实际上和错误例子是一样的效果。

    那么,我们再来看下为什么用迭代器删除时就可以安全的删除,不会报错呢?

    在他的remove函数中可以看到下面的一句话,首先其实还是调用了ArrayList的remove函数

    ArrayList.this.remove(lastRet)

    但是在调用完该函数后,他又进行了如下操作

    expectedModCount = modCount;

    相当于将最新的版本号告诉了迭代器,所以迭代器在进行异常检查的时候就不会报错,因为他俩是相等的

    四  迭代器删除元素

    public class ArrayListTest {
        public static void main(String args[]) throws Exception
        {
            List<String> strList = new ArrayList<String>();
            
            for (int i = 0; i < 10; i++)
            {
                strList.add("string" + i);
            }
            
            Iterator<String> iterator = strList.iterator();
            while (iterator.hasNext())
            {
                //iterator.next()  游标指向了下一个元素
                if (iterator.next().equals("string3"))
                {
                    iterator.remove();    //iterator.remove()移除的是最近一次iterator.next()所获取的对象
                }
            }
            
            iterator = strList.iterator();
            while (iterator.hasNext())
            {
                System.out.println(iterator.next());
            }
        }
    }

    上述代码中,iterator.remove操作移除的对象时string3。如果将蓝色while循环替换为如下的代码:

    int index = 0;
            while (iterator.hasNext())
            {
                if (++index == 3)
                {
                    iterator.remove();
                }
                System.out.println(iterator.next());

    本代码的初衷是希望通过使用迭代器来删除第三个元素即string2,并将未删除的元素依次打印出来,殊不知删除的却是string1元素,即:iterator.remove()操作删除的是上一次next元素获取的对象。因此在这里可以发现,如果要通过迭代器删除一个元素,首先要通过next方法获取该元素。

    需要删除元素,也可以把迭代器遍历过程中,把需要删除的元素放入新集合,遍历完成后一次性删除  removeAll()

  • 相关阅读:
    Linux网卡设置
    Linux虚拟机-----概述(1)
    Redis缓存数据库-----概述(1)
    Spring和Mybatis的集成
    onehot编码解释
    LINUX-CUDA版本所对应的NVIDIA驱动版本号,cuda版本报错的朋友参考一下
    matplotlib画图
    pytorch实现花朵数据集读取
    轻量架构ShuffleNet V2:从理论复杂度到实用设计准则
    CBAM: 卷积块注意模块
  • 原文地址:https://www.cnblogs.com/hup666/p/13414508.html
Copyright © 2011-2022 走看看