什么是快速失败?
优先考虑异常情况,在程序发生异常情况时,直接终止程序,向用户抛出异常。
如何产生?
在迭代输出集合时,集合发生了结构上(增加,删除)的改变。产生java.util.ConcurrentModificationException
异常。
java.util.的集合类 ,除了TreeMap
大多都采用此策略(ArrayList
、Vector
、LinkedList
、HashSet
)
例:ArrayList
集合迭代输出时,添加"hhhh"
的字符串
public class TestListIterator {
public static void main(String[] args) {
List<String> list = new ArrayList<>(); //创建好List,并给集合放入内容
list.add("hello");
list.add("world");
list.add("hello");
list.add("China");
Iterator<String> iterator = list.iterator(); //取得list的迭代器
//迭代输出list的内容
while (iterator.hasNext()) {
String str1 = iterator.next();
list.add("hhhh");
System.out.println(str1);
}
}
}
此时,程序会产生java.util.ConcurrentModificationException
异常
产生原因-源码解析
- 每调用一次
add()
方法向集合添加元素时,会使modCount
这个变量值+1
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
- 在调用
list.iterator()
迭代器对象时,会调用此方法,返回一个Itr()
对象
public Iterator<E> iterator() {
return new Itr();
}
- 而
private class Itr implements Iterator<E> {}
这个方法中,有int expectedModCount = modCount;
这个操作,将modCount
赋给了expectedModCount
- 在每次
iterator.next()
操作时,会调用next()
方法,此方法中会再调用checkForComodification();
方法。
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;
return (E) elementData[lastRet = i];
}
- 而此处会检验
modCount
和expectedModCount
是否相等,因为进行了一次add
操作,所以此时modCount
已经+1了,两者不再相等,自然会抛出ConcurrentModificationException
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如何避免?
1.不要在迭代输出集合时修改集合内容,使集合结构改变。
2.使用iterator
的修改方法。
3.使用fail-safe集合。