简书 賈小強
转载请注明原创出处,谢谢!
你将在面试中被问这个问题很多次,比如,在Java中迭代器(Iterator)如何工作的,怎么删除List中的元素?什么时候抛出IllegalStateException
? 什么时候在会抛出ConcurrentModificationException
? Iterator和ListIterator之间的区别?
什么时候抛出IllegalStateException
Java迭代器接口定义如下
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
hasNext() 如果仍有元素可以迭代,则返回 true。
next() 返回迭代的下一个元素。
remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。否则抛出IllegalStateException
,如下
Iterator<Integer> iterator1=arrayList.iterator();
iterator1.next();
iterator1.remove();
iterator1.remove(); // throws IllegalStateException
正确的方式应该是:
Iterator<Integer> iterator1=arrayList.iterator();
iterator1.next();
iterator1.remove();
iterator1.next();
iterator1.remove();
什么时候抛出ConcurrentModificationException
在Java中,当你实例化一个迭代器,当你修改集合的时候,它就会计数。如果迭代器检测到你用不是用它修改了集合(比如同一个集合的另一个迭代器),它不能保证操作的正确性,比如一个一个迭代器指向另一个迭代器刚刚删除的元素前面,现在这个迭代器就是无效的,而且不应该再被使用,迭代器的设计使它能够检测到这种修改。如果发现那么抛出ConcurrentModificationException
。
ArrayList<Integer> arrayList=new ArrayList<Integer>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
Iterator<Integer> iterator1=arrayList.iterator();
Iterator<Integer> iterator2=arrayList.iterator();
iterator1.next();
iterator1.remove();
iterator2.next(); // throws ConcurrentModificationException
由于iterator2检测出了这个List被从外部修改了,所以对iterator2.next的调用抛出ConcurrentModificationException
ArrayList的方法有一个计数器的modcount,声明为:
protected transient int modCount = 0;
当你用一个ArrayList创建一个Iterator/ListIterator,这个modCount被用来初始化Iterator对象中的一个叫expectedModCount的字段
int expectedModCount = modCount;
在ArrayList上的任何操作(不使用迭代器实例)将增加modCount。迭代器的所有方法执行前都讲检查modCount == expectedModCount。如果它们不相等,则抛出异常。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Iterator和ListIterator之间的区别
先看如下类层次关系
可以发现实现Collection接口的所有集合都可以产生Iterator
而只有实现List接口的集合(比如ArrayList,LinkedList,Vector,Stack)可以产生ListIterator
原因在于使用Iterator,比如计算集合元素的总是或者符合某种条件的元素个数这种和顺序无关的并没有问题,但因为迭代器(Iterator和ListIterator)描述了元素的位置关系,而add方法又依赖于这种位置关系,那么比如对于Set这种完全无序的集合Iterator提供add方法就不合适了(Set集合本身是根据元素的hashCode来决定元素的位置,而如果直接用迭代器add,将一个元素直接添加到上一个元素的后面,那将破坏哈希机制),于是分出了ListIterator,专门针对有序集合提供add方法
我希望以上的解释能帮助你回答这个面试问题。
Happy Learning !!