Iterator-迭代器使用和原理

迭代器简介(Iterator)

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

import java.util.Iterator;

为什么要使用迭代器

迭代模式是访问(Collection)集合类的通用方法,只要集合类实现了Iterator接口,就可以用迭代的方式来访问集合类内部的数据,Iterator访问方式把对不同集合类的访问逻辑抽象出来,使得不用暴露集合内部的结构而达到循环遍历集合的效果。Iterator模式总是用同一种逻辑来遍历集合。

Map映射如何使用迭代器?

迭代器只针对集合类型的数据,但map集合提供了keySet()方法和value()方法,可以通过先将键值输出到一个集合,可以是list集合或者set集合,再使用迭代器去获取元素。

迭代器的优点

优点:

  1. 可以不了解集合内部的数据结构,就可以直接遍历;
  2. 不暴露内部的数据,可以直接外部遍历,提高安全性;
  3. 适用性强,基本上的集合都能使用迭代器;

Iterator和ListIterator区别:

  1. ListIterator有add()方法,可以向List中添加对象,而Iterator不能
  2. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
  3. ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
  4. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。

Iterator的API

关于Iterator主要有三个方法:hasNext()、next()、remove()

  • hasNext: 没有指针下移操作,只是判断是否存在下一个元素
  • next:游标指针下移,返回 lastRet 所指向的元素
  • remove:删除lastRet 指针所指向的元素,一般和next方法一起用,这时候的作用就是删除next方法返回的元素。并将游标前移,lastRet复位。 cursor = lastRet; lastRet = -1;

Iterator.remove()是唯一安全的方式来在迭代过程中修改集合。

如果在使用迭代器的过程中有其他的线程修改了List就会抛ConcurrentModificationException,这就是Fail-Fast机制。
foreach 本质上就是 Iterator。 实际上Iterator.remove内部也调用了ArrayList.remove 只不过后面又执行了 expectedModCount=modCount 防止移除元素后next取值变成第i+2个元素。

使用iterator.remove()方法前,一定先调用next()

使用迭代器iterator.remove()方法前,一定先调用next()方法来给变量lastRet进行赋值操作。否则lastRet = -1,会抛出 IllegalStateException()异常。

fail-fast策略–从线程安全的角度考虑

所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是ArrayList修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 list:注意到 modCount 声明为 volatile,保证线程之间修改的可见性。

迭代器源码

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

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;//当前所指向元素的游标,初始iterator的游标为0
        int lastRet = -1; //上个元素的索引,默认是-1
        int expectedModCount = modCount;//modCount为ArrayList修改次数,

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];//给变量lastRet进行赋值操作。
        }

        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();
            }
        }

        final void checkForComodification(){
            if(expectedModCount != modCount)
             throw new ConcurrentModificationException();
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值