Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。
快速失败
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
list.add(3);
System.out.println(list.size());
}
}
}
运行结果:
1
Exception in thread "main" java.util.ConcurrentModificationException
3
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at Test.main(Test.java:12)
安全失败
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
public class Test {
public static void main(String[] args) {
List<Integer> list = new CopyOnWriteArrayList<>();
list.add(1);
list.add(2);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
list.add(3);
System.out.println("list size:"+list.size());
}
}
}
运行结果:
1
list size:3
2
list size:4
其实,在java.util.concurrent 并发包的集合,如 ConcurrentHashMap, CopyOnWriteArrayList等,默认为都是安全失败的。