Java迭代器一共有3种,最常用的一种是Iterator
Iterator
目前最常用的一种迭代器,在这中相当于有一个指针,指向第一个数的前面
两种主要用的方法:
1.hadNext()下一个对象是否还存在
2.next() 取出下一个数,指针指向下一位。
Iterator it=list.iterator();
for (Iterator it=list.iterator();it.hasNext();) {
System.out.println(it.next());
}
ListIterator
双向迭代器
Enumeration
相当于Iterator,现在已被取代。
解决使用迭代器删除元素抛异常问题
- 遍历对象的方法
Iterator it=list.iterator();
//方式一:使用while循环
while(it.hasNext()){
System.out.println(it.next());
}
//方式二:使用foreach,简单,不用自己创建迭代器对象,在底层仍然是迭代器的for循环。
for (Object e : list) {
System.out.println(e);
}
/*
for(Iteratorit=list.iterator();it.hasNext();e=i t.next()) {
System.out.println(e);
}
*/
- 1
由于foreach循环比较简单,所以一般我们在遍历数组和集合的时候,都会优先考虑使用它。
但是在需要边迭代边删除的情况下,不能使用foreach,必须显示写出迭代器对象,否则会报错: java.util.ConcurrentModificationException
在API中对此异常的解释如下:
public class ConcurrentModificationException extends RuntimeException
此异常可能会被抛出的方法,已检测到的对象的并发修改时,这样的修改是不允许的。
例如,它通常是不允许一个线程而另一个线程遍历它修改集合。在一般情况下,迭代的结果是不确定的,在这种情况下。一些迭代器实现(包括所有通用收集实现的JRE提供)可以选择如果检测行为抛出该异常。迭代器这样做被称为快速失败迭代器,因为他们不能迅速、干净,而冒着任意的,非在将来一个不确定的时间确定的行为。注意,这个例外并不总是表明对象已由一个不同的线程的并发性。如果一个线程问题序列的方法调用,违反合同的对象,对象可能抛出该异常。例如,如果一个线程修改直接收集的则是在一个快速失败迭代器集合的迭代,迭代器将抛出此异常。
注意,快速失败行为不能得到保证的话,一般来说,不可能在不同步的并发修改的存在作出难以保证。快速失败的操作把ConcurrentModificationException尽最大努力的基础上。因此,要写一个程序,依靠这一例外的正确性错误:concurrentmodificationexception只能用来检测错误。
- 以上情况分析:
在使用Iterator的时候,迭代器会新建一个线程,把原来的线程中的对象重新拷贝一份,在进行删除,修改等操作时,原来的线程只负责迭代,而Iterator负责迭代和删除操作,Iterator每次迭代都会检查迭代器里的对象和原线程中的对象个数是否一致,不一致则抛出:ConcurrentModificationException。
for (Object e : list) {
System.out.println(e);
if("b".equals(e)){
list.remove(e);//操作集合的删除方法
}
}
运行结果:
a
b
Exception in thread "main" java.util.ConcurrentModificationException
- 以上情况解决办法
不能使用集合中的remove方法,使用Iterrator中的remove方法。
Iterator中的remove
default void remove()
从基础集合中移除这个迭代器返回的最后一个元素(可选操作)。两个线程中都删除,保证线程的同步。
修改后的代码:
Iterator it=list.iterator();
while(it.hasNext()){
Object e=it.next();
if("b".equals(e)){
it.remove();
}
}
System.out.println(list);
总结
-
在需要的删除等操作时,不能使用简单的foreach,因为其底层依然用的是Iterator,但是调用的是集合中的remove方法。
-
使用迭代器对象调用其中的remove方法,以保证线程同步。