我要把ArrayList中的一些元素移除,但抛出了ConcurrentModificationException异常,下面是代码:
/**
* Removes all students in the specified array list whose grade
* is less than the specified grade.
*
* @param arrayList an array list of <code>Student</code> objects.
* @param grade a grade.
*/
public static void removeGradeLess(
ArrayList<Student> arrayList,
int grade) {
/* PLACE YOUR CODE HERE */
/* My code is here. ^_^ */
if (arrayList.size() == 0){
}else{
for (Student s : arrayList){
if (s.getGrade() < grade){
arrayList.remove(s);
}
}
}
}
这个是测试程序:
public boolean testRemoveGradeLess() {
setUp();
boolean test = true;
try {
StudentArrayList.removeGradeLess(emptyArrayList, 100);
test = test && assertTrue("1, testing method removeGradeLess",
emptyArrayList.size() == 0);
StudentArrayList.removeGradeLess(arrayList, 90);
test = test && assertTrue("2, testing method removeGradeLess",
arrayList.size() == 3);
test = test && assertTrue("3, testing method removeGradeLess",
arrayList.get(0) == first);
test = test && assertTrue("4, testing method removeGradeLess",
arrayList.get(1) == second);
test = test && assertTrue("5, testing method removeGradeLess",
arrayList.get(2) == fourth);
StudentArrayList.removeGradeLess(arrayListTwo, 90);
test = test && assertTrue("6, testing method removeGradeLess",
arrayListTwo.size() == 2);
test = test && assertTrue("7, testing method removeGradeLess",
arrayListTwo.get(0) == secondArrayListTwo);
test = test && assertTrue("8, testing method removeGradeLess",
arrayListTwo.get(1) == fifthArrayListTwo);
} catch (Exception e) {
test = fail("9, testing method removeGradeLess: " + e.toString());
}
return test;
}
结果是:
Testing class StudentArrayList...
** Test failure 9, testing method removeGradeLess: java.util.ConcurrentModificationException
请问高手怎么解决啊?
------解决方案--------------------
ConcurrentModificationException 的异常分析
今日运行一段如下代码
List<;Person> pList = ...
for(Person person : pList){
if(person.getGender()==Gender.MALE){
pList.remove(person);
}
}
报出的异常为 java.util.ConcurrentModificationException 异常
经查找资料
public class ConcurrentModificationExceptionextends RuntimeException
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不明确的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。
当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运行, java.util.ConcurrentModificationException 异常也将被抛出。
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。