简体   繁体   English

Java并发修改异常错误

[英]Java Concurrent Modification Exception Error

Im playing around with some code for my college course and changed a method from 我正在玩我的大学课程的一些代码,并改变了方法

public boolean removeStudent(String studentName)
{
    int index = 0;
    for (Student student : students)
    {
        if (studentName.equalsIgnoreCasee(student.getName()))
        {
            students.remove(index);
            return true;
        }
        index++;
    }
    return false;
}

To: 至:

public void removeStudent(String studentName) throws StudentNotFoundException
{
    int index = 0;
    for (Student student : students)
    {
        if (studentName.equalsIgnoreCase(student.getName()))
        {
            students.remove(index);
        }
        index++;
    }
    throw new  StudentNotFoundException( "No such student " + studentName);
}

But the new method keeps giving a Concurrent Modification error. 但是新方法不断给出并发修改错误。 How can I get round this and why is it happening? 我怎样才能解决这个问题,为什么会这样呢?

It is because you continue traversing the list after performing remove() . 这是因为您在执行remove()后继续遍历列表。

You're reading and writing to the list at the same time, which breaks the contract of the iterator underlying the foreach loop. 您正在同时读取和写入列表,这会破坏foreach循环下的迭代器的契约。

Use Iterator.remove() 使用Iterator.remove()

for(Iterator<Student> iter = students.iterator(); iter.hasNext(); ) {
    Student student = iter.next();
    if(studentName.equalsIgnoreCase(student.getName()) {
        iter.remove();
    }
}

It is described as the following: 它描述如下:

Returns the next element in the iteration. 返回迭代中的下一个元素。

Throws NoSuchElementException if the iteration has no more elements. 如果迭代没有更多元素,则抛出NoSuchElementException

You can use Iterator.hasNext() to check if there is a next element available. 您可以使用Iterator.hasNext()来检查是否有可用的下一个元素。

foreach construct uses an underlying Iterator . foreach构造使用底层Iterator

In the second method you continue to iterate even after removing an item from the list. 在第二种方法中,即使从列表中删除项目,您仍继续迭代。 This is resulting in the exception that you see. 这导致了您看到的异常。 Take a look at this statement taken from ConcurrentModificationException documentation: 看一下ConcurrentModificationException文档中的这个语句:

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. 例如,一个线程通常不允许修改Collection而另一个线程正在迭代它。 In general, the results of the iteration are undefined under these circumstances. 通常,在这些情况下,迭代的结果是不确定的。 Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. 如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。

This error occurs because you are trying to alter the size of a collection while you are iterating it. 发生此错误的原因是您在迭代时尝试更改集合的大小。 If you have 10 students, you start your loop expecting to go through 10 iterations. 如果你有10个学生,你开始循环期望经历10次迭代。 When you remove a student, how many iterations do still need to go? 删除学生时,还需要进行多少次迭代? The answer obviously depends on where you removed your student from the list and where you currently are in your iteation. 答案显然取决于您从列表中删除学生的位置以及您当前在迭代中的位置。 Obviously, java cannot know this. 显然,java无法知道这一点。

To get around this, you must use an iterator. 要解决这个问题,必须使用迭代器。 You can accomplish this as follows: 您可以按如下方式完成此操作:

Iterator<Student> studentsIterator;
for(studentsIterator = students.iterator(); studentsIterator.hasNext();)
{
    Student student = studentsIterator.next();
    if(student... /* condition */)
    {
        studentIterator.remove();  //This removes student from the collection safely
    }
}

You are not allowed to remove an element from students collection while iterating through it. 在迭代students集合时,不允许从students集合中删除元素。

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible. 当不允许这样的修改时,检测到对象的并发修改的方法可能抛出此异常。

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. 例如,一个线程通常不允许修改Collection而另一个线程正在迭代它。 In general, the results of the iteration are undefined under these circumstances. 通常,在这些情况下,迭代的结果是不确定的。

http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html

Try changing to 尝试改为

Iterator<Student> itr = students.iterator();
while (itr.hasNext()) {
    Student student = itr.next();
    if (studentName.equalsIgnoreCase(student.getName()))
    {
        itr.remove();
    }
}

If you want to remove inside a loop you should use an iterator and its remove method 如果要在循环内部删除,则应使用迭代器及其remove方法

public boolean removeStudent(String studentName)
{
    Iterator<Student> itS = students.iterator();
    while(itS.hasNext())
    {
        Student student = itS.next();
        if (studentName.equalsIgnoreCasee(student.getName()))
        {
            itS.remove();
            return true;
        }
    }
    return false;
}

You are not allowed to remove an element from your collection while you iterate over it. 在迭代它时,不允许从集合中删除元素。 The iterator detects a structural change during its usage, and throws the exception. 迭代器在其使用期间检测结构更改,并抛出异常。 Many collections are implemented in such a way. 许多集合都以这种方式实现。

Use the iterator directly instead: 直接使用迭代器:

    Iterator<Student> it = students.iterator();
    while (it.hasNext()) {
        Student student = it.next();

        if (studentName.equalsIgnoreCase(student.getName())) {
                it.remove();
                return true;
        }
    }
    return false;

You shouldn't delete objects from a collection while using a for-each statement - this will cause exceptions as your iterator faces a changed collection in the course of its iterations. 在使用for-each语句时,不应该从集合中删除对象 - 这将导致异常,因为迭代器在迭代过程中面向更改的集合。 (the for loop) either use a regular for loop (for int i = 0; i < 100; i++) etc... or keep the objects to remove in a list, and remove them outside of the for loop. (for循环)使用常规for循环(对于int i = 0; i <100; i ++)等...或者保持要在列表中删除的对象,并将它们移除到for循环之外。

Also, you remove the object by index where index is : 0 , 1 , 2 but index should actaully be the index of the student. 此外,您通过索引删除对象,其中索引为:0,1,2但索引应该通常是学生的索引。

你可以避免并发修改错误购买只是在删除元素后打破循环或者如果方法有一个返回类型在删除元素后返回一个值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM