大家看看这个代码有什么问题,我的想法是删除list的第一个元素
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("aaaa");
list.add("bbbb");
List<String> subList=new ArrayList<String>();
subList=list.subList(0, 1);
list.removeAll(subList);
}
然后北极的发型报错了:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.SubList.checkForComodification(AbstractList.java:752)
at java.util.SubList.listIterator(AbstractList.java:682)
at java.util.AbstractList.listIterator(AbstractList.java:284)
at java.util.SubList.iterator(AbstractList.java:678)
at java.util.AbstractCollection.contains(AbstractCollection.java:82)
at java.util.AbstractCollection.removeAll(AbstractCollection.java:336)
at com.T.main(T.java:15)
为什么呢?想不通啊。后来才发现这个是subList引起的:
subList其实是保留了原来的list的一个引用的
class SubList<E> extends AbstractList<E> {
private AbstractList<E> l;
private int offset;
private int size;
private int expectedModCount;
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<E>(this, fromIndex, toIndex) :
new SubList<E>(this, fromIndex, toIndex));
}
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
offset = fromIndex;
size = toIndex - fromIndex;
expectedModCount = l.modCount;
}
可以看到是通过this把原来的list传进去的,subList其实是保留了原来的list的引用。
当执行removeAll的时候,会去subList遍历所有的元素,符合条件的就删除,list的每个操作都会modCoun加一
public E remove(int index) {
RangeCheck(index);
modCount++;
而subList的next操作会去检查这个值,(注意subList检查的是引用list的modCount,他没有自己的)。
private void checkForComodification() {
if (l.modCount != expectedModCount)
throw new ConcurrentModificationException();
}
所以list.removeAll(subList);
public boolean removeAll(Collection<?> c) {
boolean modified = false;
Iterator<?> e = iterator();
while (e.hasNext()) {
if (c.contains(e.next())) {
e.remove();
modified = true;
}
}
return modified;
}
必然会执行subList的next,如果list已经删掉了一个元素,那么modCount 必定会改变,就会抛出异常了。