JDK8源码之Iterator顺序遍历迭代器

Iterator是什么?

public interface Iterator<E> {...}

iterator被称之为顺序遍历迭代器,jdk中默认对集合框架中数据结构做了实现。iterator在实际应用中有一个比较好的点就是,可以一边遍历一遍删除元素(不过需要自实现,好在jdk都帮你做了,哈哈),后面拿ArrayList.iterator()来说明怎么做到这点的。

Iterator结构

 //是否能遍历到下一个元素。是返回true,否则返回false
 boolean hasNext();
 //指向下一个元素
 E next();
 //删除当前元素,需要实现者重写,默认会抛错
 default void remove() {
       throw new UnsupportedOperationException("remove");
   }
  //顺序遍历元素,对每个元素执行指定事件,一直到遍历完所有元素
 default void forEachRemaining(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    while (hasNext())
        action.accept(next());
    }

ArrayList.iterator()解析

 public Iterator<E> iterator() {
        //返回一个顺序遍历迭代器
        return new Itr();
    }

 private class Itr implements Iterator<E> {
     //指向下次将遍历到的位置
     int cursor;   
     //当前遍历到的位置,当为-1时,表示未指向元素   
     int lastRet = -1;
     //结构变更次数
     int expectedModCount = modCount;

    //是否返拥有下个元素
     public boolean hasNext() {
         return cursor != size;
     }

     //遍历到下个元素
     @SuppressWarnings("unchecked")
     public E next() {
         //ArrayList是否发生结构变更操作
         checkForComodification();
         //得到当前遍历的位置
         int i = cursor;
         //是否超出size大小
         if (i >= size)
             throw new NoSuchElementException();
         Object[] elementData = ArrayList.this.elementData;
         //并发修改异常,elementData的结构发生变更
         //(疑惑:这一段代码的意义,可以和forEachRemaining对比一下)
         if (i >= elementData.length)
             throw new ConcurrentModificationException();
          //指向下次遍历到的位置
         cursor = i + 1;
         //返回当前位置的值
         return (E) elementData[lastRet = i];
     }

     public void remove() {
         //如果当前遍历器未指向任何元素时,则报错
         //未执行next()时和执行remove方法时 lastRet=-1
         if (lastRet < 0)
             throw new IllegalStateException();
         checkForComodification();

         try {
             //调用arrayList.remove方法来删除元素
             ArrayList.this.remove(lastRet);
             //指针指向当前删除位置
             cursor = lastRet;
             //lastRet置为-1,表示当前遍历器未指向任何元素
             lastRet = -1;
             //这里是iteraotr可以遍历到元素后可以删除元素的关键
             expectedModCount = modCount;
         } catch (IndexOutOfBoundsException ex) {
             throw new ConcurrentModificationException();
         }
     }

     @Override
     @SuppressWarnings("unchecked")
     public void forEachRemaining(Consumer<? super E> consumer) {
         //consumer不能为空校验
         Objects.requireNonNull(consumer);
         final int size = ArrayList.this.size;
         int i = cursor;
         //遍历器还有元素未遍历完
         if (i >= size) {
             return;
         }
         final Object[] elementData = ArrayList.this.elementData;
         //并发修改异常,elementData的结构发生变更(这一段代码的意义,可以思考下)
         if (i >= elementData.length) {
             throw new ConcurrentModificationException();
         }
         //遍历元素执行指定动作
         while (i != size && modCount == expectedModCount) {
             consumer.accept((E) elementData[i++]);
         }
         // update once at end of iteration to reduce heap write traffic
         cursor = i;
         lastRet = i - 1;
         checkForComodification();
     }

     final void checkForComodification() {
         if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
     }
 }

看到这一段代码的时候,我对forEachRemaining方法里面检查ConcurrentModificationException并发操作异常的情况有疑惑,在校验元素的size后,再将执行 Object[] elementData = ArrayList.this.elementData;再对elementData进行遍历操作同时并会对expectedModCount进行判断,因此遍历之前检查(i >= elementData.length) 感觉并没有什么用。

另外,ArrayList自身就不是线程安全的,modCount也只是用来保证快速失败,因此不要在多线程的环境下使用iterator进行并行遍历操作。如果需要并行遍历可以使用Spliterator进行并行遍历。

ArrayList.iterator本质上还是操作原list对象,只是通过一个单向指向list的索引而对原对象进行引用,因此iterator在工作的时候,我们如果对远list对象进行了结构上的变更,此时会通过expectedModCount比较modCount是否相等来实现fail-fast。而ArrayList.iterator.remove方法没有问题,是因为操作过后会同步更新expectedModCount的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值