2014-10-22 5 views
1

Я пытаюсь использовать итератор, но это дает мне эту ошибку:Использование класса итератора в Java

java.util.concurrentModificationException: null (in java.util.ArrayList$Itr)

Код находится здесь:

import java.util.ArrayList; 
import java.util.Iterator; 

public class Iteratorr 
{  
    ArrayList<String> list = new ArrayList<>(); 
    Iterator<String> it = list.iterator(); 

    void add() 
    { 
    list.add("Hello"); 
    list.add("I"); 
    list.add("am"); 
    list.add("ArrayList"); 
    } 

    void print() 
    { 
    while(it.hasNext()) 
    { 
     String str = it.next(); 
     System.out.println(str); 
    } 
    }  
} 

Может кто-нибудь объяснить причину?

+0

потому что вы создаете итератор в init, и после этого обязательно вызывается 'add'. следовательно, одновременная модификация – njzk2

ответ

3

Последовательность событий выглядит следующим образом:

  1. создается итератор для (пустого) списка.
  2. Вы добавляете элементы в список.
  3. Вы начинаете использовать итератор, созданный на шаге 1.

Это не будет работать, потому что шаг 2 был признан недействительным итератора. Это то, о чем вам говорит исключение. Из Javadoc:

The iterators returned by [ ArrayList 's] iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException .

Вам нужно создать итератор, прежде чем начать итерацию:

public class Iteratorr 
{  
    ... 
    Iterator<String> it = null; 

    void print() { 
    it = list.iterator(); 
    while(it.hasNext()) { 
     String str = it.next(); 
     System.out.println(str); 
    } 
    }  

(еще лучший способ будет объявить it внутри print, а не в качестве члена класса .)

в эти дни идиоматический способа писать такую ​​петлю является

void print() { 
    for (String str : list) { 
     System.out.println(str); 
    } 
    }  

Он имеет тот же эффект, что и явный итератор, но гораздо проще на глазу.

+0

Я помню (но нуждаюсь в подтверждении), что компилятор заменяет for-each петли на петли while-iterator. Так что это действительно только для глаз, и мои глаза любят это;) – AxelH

0

что Excpption зависит от способа вызова метода. Вы можете использовать переменные локально в методе следующим образом.

void print() 
{ 
    ArrayList<String> list = new ArrayList<>(); 

    //Add elements here 
    add(list); 

    Iterator<String> it = list.iterator(); 

    while(it.hasNext()) { 

     String str = it.next(); 

     System.out.println(str); 
    } 

} 

void add(List list) 
    { 
     list.add("Hello"); 
     list.add("I"); 
     list.add("am"); 
     list.add("ArrayList"); 
    } 
2

Вы должны получить итератор после внесения последних изменений в список! В противном случае это будет другой итератор, который не «знает» содержимое нового Списка.

Более изящный способ использования (по умолчанию) итератор неявным:

void print() 
{ 
    for(String str : list) 
    { 
     System.out.println(str); 
    } 
} 

Хотя это может быть лучше для понимания, особенно если вы хотите определить свой итератор позже:

void print() 
{ 
    Iterator<String> it = list.iterator(); 

    while(it.hasNext()) 
    { 
     System.out.println(it.next()); 
    } 
} 
Смежные вопросы