java开发:java集合(七):迭代器的fail-fast(快速失败)机制

Inteator 是顶层的迭代器接口,定义了迭代器共同的方法。hasNext()判断集合是否含有下一个元素,next()获取下一个元素。每个具体的集合类中都有一个迭代器内部类实现于Inteator接口,用来历遍集合。

为了方便获取迭代器对象,java还提供了Iterable接口,使用iterator()方法来获取集合的迭代器。Collection 继承于Iterable接口,而所有具体的集合类都实现了Collection 。因此在我们使用集合时只需要调用集合对象的iterator()方法便可以得到迭代器对象。

/**
迭代器顶层接口
**/
public interface Inteator {
	public abstract boolean hasNext();
	public abstract Object next();
}

/**
获取迭代器对象的顶层接口
**/
public interface Iterable {
	Iterator iterator();
}

/**
Collection接口 继承Iterable
**/
public interface Collection extends Iterable {
	Iterator iterator();
}
public interface List extends Collection {
	Iterator iterator();
}
public calss ArrayList implements List {
	public Iterator iterator() {
		return new Itr();
	}
	private class Itr implements Iterator { //接口的具体实现类
		//包含了 所需功能  next()    hasNext() 等
	}
}

既然我们大概明白了迭代器的一个整体结构,我们来使用试一下:

   ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        //获取迭代器
        Iterator iterator = list.iterator();
        //历遍集合
        while (iterator.hasNext()) {
            Log.e("iterator",iterator.next().toString());
        }
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 1
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 2
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 3
2019-12-27 14:22:17.069 6360-6360/com.example.serializationapplication E/iterator: 4

实验成功,可以迭代我们集合的所有元素,那么我们试试在迭代过程中修改集合会怎么样?

  ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        //获取迭代器
        Iterator iterator = list.iterator();
        //历遍集合
        while (iterator.hasNext()) {
            Log.e("iterator",iterator.next().toString());
            //移除第一个元素
            list.remove(0);
        }

控制台报出了异常: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.serializationapplication/com.example.Main3Activity}: java.util.ConcurrentModificationException

解析ArrayList的迭代器源码:

 private class Itr implements Iterator<E> {
        int cursor;       // 记录元素下标的指针
        int lastRet = -1; // 记录当前元素下标位置的指针
        int expectedModCount = modCount;//记录集合修改的次数索引

		//判断集合是否含有下一个元素
        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();
            //指针+1,指向下一个元素
            cursor = i + 1;
            //返回当前元素,修改lastRet 指向当前的元素
            return (E) elementData[lastRet = i];
        }

        public void remove() {
        	//当lastRet小于0则集合为null
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
            	//删除元素
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                //更新集合修改次数的索引
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.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();
        }
    }

可以看出在ItrArrayList的一个内部类,迭代器操作通过这个内部类,Itr有个expectedModCount属性,这个属性判断是否与modCount相等,如果不相等抛出异常,modCount则是记录list结构上发生变化的次数,可以看出在迭代时候checkForComodification()方法检测两个的值不相等就抛出异常。则出现这个异常的时候一般都是在迭代过程中改变了集合,导致modCountexpectedModCount属性不相等。迭代器则提供了remove()方法来移除元素,在删除元素后同时更新modCountexpectedModCount属性,因此不会报异常。

发布了194 篇原创文章 · 获赞 42 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_39027256/article/details/103730877