有时候会有这种场景,在遍历list的过程中,需要删除掉一部分元素。如果不注意的话,很容易就写出下面的代码:
public class ListRemoveTest {
public static void main(String[] args) {
List<String> removeList = new ArrayList<String>();
removeList.add("a");
removeList.add("b");
removeList.add("c");
removeList.add("d");
for (int i = 0; i < removeList.size(); i++) {
removeList.remove(i);
}
System.out.println(removeList.size());
}
}
程序的运算结果输出为2,本以为会输出0,但是为什么是2呢?下面看下ArrayList的remove方法源码:
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
/**
* Checks if the given index is in range. If not, throws an appropriate
* runtime exception. This method does *not* check if the index is
* negative: It is always used immediately prior to an array access,
* which throws an ArrayIndexOutOfBoundsException if index is negative.
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
当传入要删除的位置index之后,rangeCheck方法会先进行判断,如果index大于等于数组的长度,则直接抛出IndexOutOfBoundsException异常。然后modCount加1(涉及到快速失败机制,此处略过)。
之后会利用 System.arraycopy方法,把index位置后面的元素向前拷贝一个位置。再把最后一个位置置为null,方便进行垃圾回收。所以,当调用list.remove()方法时,这个list就变了。
上面代码中,当i=0的时候,第一次调用remove方法,把第一个元素删除掉之后,list的size就变成3了,并且原来第二个位置的元素被拷贝到了第一个位置。接下来i=1,实际删除掉是原来第三个元素。等原来的第三个元素删除后,list的size变成了2,然后i=2,再remove(2)的时候,此时这个位置已经没有元素了。所以最后还会剩下b和d两个元素。
所以,直接用这种方式删除是不可以的,如果要删除list中的元素的话,需要通过迭代器。
List<String> iteratorList = new ArrayList<String>();
iteratorList.add("1");
iteratorList.add("2");
iteratorList.add("3");
Iterator iterator = iteratorList.iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
System.out.println(iteratorList.size());
程序输出结果:0