10

大学のコースのコードをいじって、メソッドをから変更しました

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;
}

に:

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);
}

しかし、新しいメソッドは並行変更エラーを出し続けます。どうすればこれを回避できますか?なぜそれが起こっているのですか?

4

8 に答える 8

21

を実行した後もリストをトラバースし続けるためですremove()

リストの読み取りと書き込みを同時に行っているため、foreachループの基礎となるイテレーターのコントラクトが壊れています。

使用するIterator.remove()

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

それは次のように説明されています:

反復の次の要素を返します。

反復NoSuchElementExceptionにこれ以上要素がない場合にスローします。

Iterator.hasNext()使用可能な次の要素があるかどうかを確認するために使用できます。

于 2013-03-13T11:52:18.017 に答える
2

foreachコンストラクトは基になるを使用しIteratorます。

2番目の方法では、リストからアイテムを削除した後も繰り返しを続けます。これにより、表示される例外が発生します。ConcurrentModificationExceptionドキュメントから取られたこのステートメントを見てください:

たとえば、別のスレッドがコレクションを反復処理しているときに、あるスレッドがコレクションを変更することは一般的に許可されていません。一般に、これらの状況では、反復の結果は定義されていません。一部のIterator実装(JREによって提供されるすべての汎用コレクション実装の実装を含む)は、この動作が検出された場合にこの例外をスローすることを選択する場合があります。

于 2013-03-13T11:53:45.270 に答える
1

コレクションを反復処理している間は、コレクションから要素を削除することはできません。イテレータは、使用中に構造の変更を検出し、例外をスローします。多くのコレクションはそのような方法で実装されています。

代わりにイテレータを直接使用してください。

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

        if (studentName.equalsIgnoreCase(student.getName())) {
                it.remove();
                return true;
        }
    }
    return false;
于 2013-03-13T11:53:26.103 に答える
1

要素を削除した後にループを壊すだけの同時変更エラー購入を回避できます。または、メソッドに戻り型がある場合は、要素を削除した後に値を返します。

于 2014-07-22T07:31:16.363 に答える
0

このエラーは、コレクションを反復処理しているときにコレクションのサイズを変更しようとしているために発生します。10人の生徒がいる場合は、10回の反復を期待してループを開始します。生徒を削除する場合、まだ何回繰り返す必要がありますか?答えは明らかに、あなたがあなたの生徒をリストから削除した場所とあなたが現在あなたの考えのどこにいるかに依存します。明らかに、Javaはこれを知ることができません。

これを回避するには、イテレータを使用する必要があります。これは次のように実行できます。

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
    }
}
于 2013-03-13T11:53:16.710 に答える
0

反復中にコレクションから要素を削除することは許可されていません。students

この例外は、オブジェクトの同時変更が許可されていない場合に、そのような変更を検出したメソッドによってスローされる可能性があります。

たとえば、別のスレッドがコレクションを反復処理しているときに、あるスレッドがコレクションを変更することは一般的に許可されていません。一般に、これらの状況では、反復の結果は定義されていません。

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

に変更してみてください

Iterator<Student> itr = students.iterator();
while (itr.hasNext()) {
    Student student = itr.next();
    if (studentName.equalsIgnoreCase(student.getName()))
    {
        itr.remove();
    }
}
于 2013-03-13T11:53:16.907 に答える
0

ループ内を削除する場合は、イテレータとその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;
}
于 2013-03-13T11:53:24.480 に答える
0

for-eachステートメントを使用している間は、コレクションからオブジェクトを削除しないでください。反復中に変更されたコレクションにイテレーターが直面するため、例外が発生します。(forループ)通常のforループ(for int i = 0; i <100; i ++)などを使用するか、削除するオブジェクトをリストに保持して、forループの外側で削除します。

また、インデックスでオブジェクトを削除します。ここで、インデックスは0、1、2ですが、インデックスは実際には生徒のインデックスである必要があります。

于 2013-03-13T11:54:41.913 に答える