2013-07-26 3 views
0

У меня есть следующий пример кода java generics, который я модифицировал в соответствии с предложением людей в StackOverflow. Теперь компиляция проходит.java generics runtime error.java.util.ConcurrentModificationException

import java.util.*; 

public class GenericBox<T> 
{ 

     private List<T> tList; 
     private Iterator<T> itor; 

     public GenericBox() 
     { 
       tList = new ArrayList<T>(); 
       itor = tList.listIterator(); 
     } 

     public void insert(T element) 
     { 
       tList.add(element); 
     } 

     public T retrieve() 
     { 
       if(itor.hasNext()) 
       { 
         return itor.next(); 
       } 
       return null; 
     } 

     public static void main (String [] args) 
     { 

       GenericBox <String> strbox = new GenericBox<String>(); 
       GenericBox <String> intbox = new GenericBox<String>(); 

       strbox.insert(new String("karthik")); 
       strbox.insert(new String("kanchana")); 
       strbox.insert(new String("aditya")); 


       String s = strbox.retrieve(); 
       System.out.println(s); 

       s = strbox.retrieve(); 
       System.out.println(s); 

       s = strbox.retrieve(); 
       System.out.println(s); 
     } 
} 

Я получаю следующую ошибку времени выполнения.

Exception in thread "main" java.util.ConcurrentModificationException 
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819) 
    at java.util.ArrayList$Itr.next(ArrayList.java:791) 
    at GenericBox.retrieve(GenericBox.java:24) 
    at GenericBox.main(GenericBox.java:40) 

ответ

5

Это не имеет ничего общего с генериков, и все делать с тем, что вы модифицирующих коллекцию непосредственно (в insert), а затем пытается использовать итератор, который был создан перед вставкой. Не делай этого.

Из документов в ArrayList:

Итераторов возвращаемых итераторы и ListIterator методов этого класса является отказоустойчивость быстро: если список конструктивно изменен в любое время после того, как итератор создается, в любом случае, кроме через собственные методы удаления или добавления итератора, итератор будет вызывать исключение ConcurrentModificationException. Таким образом, перед лицом одновременной модификации итератор быстро и чисто, а не рискует произвольным, недетерминированным поведением в неопределенное время в будущем.

Если вы должны держать итератор вокруг, используйте что добавить новое значение вместо:

private ListIterator<T> itor; // Not just Iterator<T>; you need the add method 

public void insert(T element) 
{ 
    itor.add(element); 
} 

Было бы лучше не держать итератор вокруг, хотя - это очень реже хорошая идея использовать итератор, кроме как для прямого цикла.

1

Вы получаете это исключение, потому что список был изменен между созданием итератора и его использованием. Вы должны только позвонить iterator(), когда вы действительно хотите перебирать список. Не раньше, чем. И вы не должны хранить итератор в поле экземпляра. Только в локальной переменной.

+0

Вы говорите, что итератор не должен быть переменной экземпляра. Каждый метод должен создать копию своего собственного конструктора? Является ли принятая/рекомендуемая практика кодирования? – liv2hak

+1

Итератор может использоваться только один раз. И вы не можете изменять коллекцию во время ее использования. Когда вы хотите итерации, вы задаете новый итератор коллекции, это так просто. В большинстве случаев вам даже не нужен итератор: цикл for-each создает один для вас: 'for (T element: tList) ...' –