我有以下类用于检查通过使用foreach循环从arraylist中删除对象
import java.util.ArrayList;
public class CheckArrayList {
/**
* @return the a
*/
public int getA() {
return a;
}
/**
* @param a
* the a to set
*/
public void setA(int a) {
this.a = a;
}
/**
* @return the b
*/
public int getB() {
return b;
}
/**
* @param b
* the b to set
*/
public void setB(int b) {
this.b = b;
}
int a;
int b;
public static void main(String[] args) {
try {
CheckArrayList checkArrayList1 = new CheckArrayList();
checkArrayList1.setA(10);
checkArrayList1.setB(20);
CheckArrayList checkArrayList2 = new CheckArrayList();
checkArrayList2.setA(30);
checkArrayList2.setB(40);
ArrayList<CheckArrayList> aList = new ArrayList<CheckArrayList>();
aList.add(checkArrayList1);
aList.add(checkArrayList2);
System.out.println("size of list before iterate = " + aList.size());
for (CheckArrayList checkArrayList : aList) {
aList.remove(checkArrayList);
System.out.println("inside loop");
}
System.out.println("size of list after iterate = " + aList.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
在执行上述操作时,它没有显示任何异常,但它只在循环中出现一次。
如果我向ist添加一个对象并执行相同操作,则显示java.util.ConcurrentModificationException
import java.util.ArrayList;
public class CheckArrayList {
/**
* @return the a
*/
public int getA() {
return a;
}
/**
* @param a
* the a to set
*/
public void setA(int a) {
this.a = a;
}
/**
* @return the b
*/
public int getB() {
return b;
}
/**
* @param b
* the b to set
*/
public void setB(int b) {
this.b = b;
}
int a;
int b;
public static void main(String[] args) {
try {
CheckArrayList checkArrayList1 = new CheckArrayList();
checkArrayList1.setA(10);
checkArrayList1.setB(20);
CheckArrayList checkArrayList2 = new CheckArrayList();
checkArrayList2.setA(30);
checkArrayList2.setB(40);
CheckArrayList checkArrayList3 = new CheckArrayList();
checkArrayList3.setA(30);
checkArrayList3.setB(40);
ArrayList<CheckArrayList> aList = new ArrayList<CheckArrayList>();
aList.add(checkArrayList1);
aList.add(checkArrayList2);
aList.add(checkArrayList3);
System.out.println("size of list before iterate = " + aList.size());
for (CheckArrayList checkArrayList : aList) {
aList.remove(checkArrayList);
System.out.println("inside loop");
}
System.out.println("size of list after iterate = " + aList.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果arralist大小等于2,为什么它不显示异常?
答案 0 :(得分:3)
要回答为什么它不会在2个元素上抛出错误,你必须看看每个循环实际上做了什么。for(Type something:myList)
编译成如下:
Iterator<Type> iter = myList.iterator();
while(iter.hasNext()){
Type something= iter.next()
//your code
}
现在查看实际实现的ArrayList
源代码。 hasNext()
的代码是:
return cursor != size; //cursor is the current position in the list
因此,当您删除循环中的元素时,size
现在为1.当它查看是否有更多元素时,它将返回false,因为它认为它位于ArrayList的末尾,并且此时停止执行循环。
现在查看next()
的代码:
public E next() {
checkForComodification();
//more code
}
这是实际检查修改的地方,所以当size为3时,它将执行第二次迭代,当它调用next()
来获取第二个元素时,它会抛出异常因为你修改了迭代器之外的ArrayList。
答案 1 :(得分:2)
您必须使用Iterator接口来完成此任务。
Iterator iterator = aList.iterator();
while(iterator.hasNext) {
CheckArrayList obj = iterator.next();
// use some condition to check which object to remove
if(condition) {
iterator.remove();
}
}
编辑:回答您的编辑。 您正在迭代列表从0到SIZE,并在循环中删除项目(已经违反了最佳实践)。此删除操作会减小列表的大小,当您尝试访问大于有效大小的索引(删除项目后的大小)时,该列表将失败。
来自Java文档
此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出一个ConcurrentModificationException。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的,非确定性行为的风险。
希望这有帮助。