Почему один цикл вызывает исключение ConcurrentModificationException, а другой - нет?

Я столкнулся с этим во время написания программы Traveling Salesman. Для внутреннего цикла я попробовал

for(Point x:ArrayList<Point>) {
// modify the iterator
}

но при добавлении другой точки в этот список вызывается ConcurrentModicationException.

Однако, когда я изменил цикл на

for(int x=0; x<ArrayList<Point>.size(); x++) {
// modify the array
}

цикл работал нормально, не вызывая исключения.

Как для циклов for, так почему вы выбрали исключение, а другое - нет?

Ответ 1

Как объясняют другие, итератор обнаруживает модификации базовой коллекции, и это хорошо, поскольку это может вызвать неожиданное поведение.

Представьте этот код без итератора, который изменяет коллекцию:

for (int x = 0; list.size(); x++)
{
  obj = list.get(x);
  if (obj.isExpired())
  {
    list.remove(obj);
    // Oops! list.get(x) now points to some other object so if I 
    // increase x again before checking that object I will have 
    // skipped one item in the list
  }
}

Ответ 2

В первом примере используется итератор, второй - нет. Это итератор, который проверяет одновременную модификацию.

Ответ 3

первый код использует итератор, поэтому изменение коллекции не допускается. Второй код, к которому вы обращаетесь к каждому объекту с помощью x.get(i), поэтому не используете итератор, таким образом допускаются модификации

Ответ 4

Вы не можете изменить List, пока вы повторяете его, что вы делаете в первом примере. Во втором вы просто имеете регулярный цикл for.

Ответ 5

Если вы запустите код и наблюдаете, что вы обнаружите, что первая итерация цикла работает нормально, а вторая выбрасывает ConcurrentModicationException

if, потому что метод next() проверяет, не изменилось ли число элементов.

Для приятного объяснения см. http://javaadami.blogspot.com/2007/09/enhanced-for-loop-and.html