瞧瞧bug
1. 问题代码段描述
List<Obj> objList = ObjUtil.getObjList();
if(null != objList && !objList.isEmpty()){
for(Obj p :objList){
if(p.getCode().equals(str)){
objList.remove(p);
}
}
}
2.bug描述
遇到了如下Exception:
Caused by: java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
3.问题描述
这个错误从意思上容易看出来,是在for each迭代同时执行删除操作时发生的。即枚举操作和删除操作同步执行时候会抛出同步异常。
注:for each的实现其实是使用Iterator进行迭代的,即元素枚举。
4.解决方案
个人想到一个个人认为较好的解决方案,其执行的时间复杂度为o(n),空间复杂度为o(1),主要就是用index i,j,遍历一般将待删除的元素放到List的最后;然后对List取subList(0,i+1).注意这里自己没有实用remove方法,因为看了List remove操作的代码你就会明白,每删除一个操作,需要调用System.arraycopy将后面的元素拷贝上前,直观看,个人认为这个性能不是很好,尤其该代码不是仅删除一个元素,而是针对元素值进行删除的,当然啦,据说System.arraycopy性能蛮高,还没看,有时间看看研究一下。。
代码如下:
if(null != objList && !objList.isEmpty()){
int i=0, len = objList.size();
for (; i<len; i++) {
if (objList.get(i).getCode().equals("gewala")) {
objList.set(i--, objList.get(len-1));
objList.set(--len, null);
}
}
objList = objList.subList(0, len);
}
注:subList操作并不会为数组开辟新的空间,因此空间复杂度不会是O(n),另外这也使得我们不能随意的对subList做修改,否则对原始List也进行的相同操作,如果想修改最后new开辟新的空间。
陷阱bug:使用上面代码是存在一个风险的,就是在对objList的后面元素设置为null时,会导致元素的个数与List的size不一致的问题,所以该方法在缓存重复使用时可能会造成陷阱奥。。O(∩_∩)O~,解决办法很简单,修改null那条语句就可以,这里不再赘述啦。。。