为什么阿里巴巴代码规范不允许for循环里使用add/remove方法
主要是remove方法,add方法在for循环内使用不当可能会死循环
不要在foreach循环里进行元素的remove/add操作,remove元素请使用Iterator方式。
Negative example:
List<String> originList = new ArrayList<String>();
originList.add("22");
for (String item : originList) {
//warn
list.add("bb");
}
Positive example:
Iterator<Integer> it=b.iterator();
while(it.hasNext()){
Integer temp = it.next();
if (delCondition) {
it.remove();
}
}
List的remove方法&Iterator的remove方法
// ArrayList.remove
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;
}
// ArrayList.iterator().remove
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
List的remove问题:
从源码中可以看出,举例size为10,index=4时在循环内调用了List的remove方法;
将会把下标5~9的元素copy到下标4~8,并将下标9置为null;
但是当前for循环已经处理了下标4,下次直接处理下标5,这样就导致新copy到下标4的属性被漏掉;
Iterator的处理:
从源码中可以看出Iterator中也是调用的同一个remove方法,但是将cursor重新赋值为刚处理的下标;
以上面的例子当调用next方法获取到index=4的元素时cursor=5,如果调用Integer的remove方法,内部调用完List的remove方法后,cursor被置为4;
这样再次调用next方法时就还获取index=4的元素,就不会遗漏数据了