action) { Objects.requireNo_.iterator().next()">
当前位置:   article > 正文

java中的Iterator迭代器及源码分析_.iterator().next()

.iterator().next()

迭代器接口:

public interface Iterator<E> {
	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());
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用方法:

		ArrayList list=new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

迭代器通常被称为轻量级对象(lightweight object):创建它的代价小。因此,经常可以看到一些对迭代器有些奇怪的约束。例如,Java 的 Iterator 只能单向移动。–摘自《java编程思想》
我们拿ArrayList举例,它实现了Collection接口中的Iterator iterator();方法
实现:

  public Iterator<E> iterator() {
        return new Itr();
    }
  • 1
  • 2
  • 3

new Itr()是ArrayList里面的内部类,该内部类实现了Iterator接口,重写了上面写的Iterator中的四个方法
事实上还有一个方法

     final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
  • 1
  • 2
  • 3
  • 4

这个方法在next()方法一开始就被调用:

public E next() {
   checkForComodification();
     ......
}
  • 1
  • 2
  • 3
  • 4

expectedModCount是预计修改次数,在我们一开始创建iterator的时候就会赋值,后面就不会改变
modCount 是修改次数
ArrayList中,当我们添加元素的时候,modCount++,这时候modCount != expectedModCount,checkForComodification抛出异常,这就是为什么,迭代器遍历的时候不能添加元素的原因。如果想添加元素,可以使用ListIterator(下面会提到)

iterator.next()方法可以理解为从起始位置 越过 第一个元素 来到到 第一个元素与第二个元素之间的位置,返回刚刚越过的元素的引用也就是AAA
在这里插入图片描述
remove方法会删除上次调用next方法时返回的元素,所以如果要想删除一个元素实现要越过它。
如果我们要删除BBB和CCC我们需要

Iterator iterator = list.iterator();
iterator.next();
iterator.next();//来到BBB和CCC中间
iterator.remove();//删除BBB
iterator.next();//来到CCC右边
iterator.remove();//删除CCC

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用iterator不需要知道它所遍历的序列的类型信息

ListIterator

有一点需要注意:ArrayList,LinkedList是有序集合,迭代器从头遍历到尾,这也就意味着,像add这种依赖位置的方法可以实现,并且依赖于迭代器来实现。而像Set,Map这样的无序集合就不能add,只能使用Iterator,为了让list实现迭代器的add,我们有提供了ListIterator。

ListIterator的add方法添加的元素位置在迭代器前面
ListIterator还可以从尾往头遍历

boolean hasPrevious();
E previous();
  • 1
  • 2

当从尾往头遍历时,remove()删除的是右边的元素(也是刚刚越过的元素)

add方法只依赖迭代器的位置,而remove方法不同,它依赖迭代器的状态
所以add方法可以连续调用多次,而remove方法不可以连续调用两次

另外ListIterator还有一个方法:

void set(E e);
  • 1

是用一个新元素替换调用next或preivous方法返回的上一个元素

迭代器模式(23种设计模式之一):

  1. 迭代器模式属于行为模式
  2. 迭代器遍历这种方式不会暴露元素内部结构(比如有数组,有java集合类,或者其他什么方式),不需要知道你的类型也可以遍历
  3. 迭代器模式,提供统一遍历集合元素的接口,用一致的方式遍历集合元素

List中的迭代器

    public Iterator<E> iterator() {
        return new Itr();
    }
  • 1
  • 2
  • 3

返回的是一个Itr内部类,它实现了Iterator接口

   private class Itr implements Iterator<E> {
        int cursor;       // 要返回的下一个元素的索引
        int lastRet = -1; // 返回的最后一个元素的索引; 如果最后一个元素被删除了就返回-1(在remove中会被赋值为-1)
        int expectedModCount = modCount;  //判断是否更改list结构(通过list.add()添加,list.remove()删除,注意:list里面的修改set(index,value)不改变表结构)

        Itr() {}
        
        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;
            //把当前元素(也就是刚刚越过去的元素)的位置赋值给lastRet
            return (E) elementData[lastRet = i];
        }

		public void remove() {
			//确保删除前已经next()了
            if (lastRet < 0)
                throw new IllegalStateException();
                //迭代器remove前会做是否更改list结构的判断
            checkForComodification();

            try {
            	//迭代器中的remove也是使用list.remove()
                ArrayList.this.remove(lastRet); //lastRet刚刚越过去元素的下标
                cursor = lastRet;
				//删除后就被赋值为-1,上面是if (lastRet < 0)
				//这就是为什么迭代器不能连续删除元素的原因
				//lastRet 也可以理解为迭代器的状态,-1为删除元素后的状态
                lastRet = -1;	
                //这段代码改变了expectedModCount
                //只许州官放火,不许百姓点灯
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/145600
推荐阅读
相关标签