subList引发的血案


大家看看这个代码有什么问题,我的想法是删除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 必定会改变,就会抛出异常了。

你可能感兴趣的:(list)