[Java] Очередь в цикле while, не можете изменить значение? - PullRequest
2 голосов
/ 11 мая 2010

Это мой код:

Iterator it = queue.iterator();

while(it.hasNext()){
   random = randNumber(1,2);
        if(random == 1){
            queue.poll();
        } else {
            queue.add("new");
            queue.poll();
        }
}

Это дает мне:

Exception in thread "test" java.util.ConcurrentModificationException
    at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
    at java.util.LinkedList$ListItr.next(LinkedList.java:696)

Редактировать @Jon Skeet:

Что я хочу сделать, это:

  • У меня есть список очередей, скажем, размер 10, скажем: a, b, c, d ... j
  • Создать число от 1 до 2. Если 1, потяните (уберите верхний элемент), если 2 добавьте новый элемент
  • Я остановлю цикл, пока не добавлю 3 новых элемента

Ответы [ 4 ]

7 голосов
/ 11 мая 2010

Как правило, вы не можете изменять коллекции, пока выполняете их. Один из вариантов - создать отдельный список «изменений», которые вы хотите применить, и затем применить их после завершения итерации.

В качестве альтернативы, некоторые коллекции do поддерживают это, например ConcurrentLinkedQueue, но большинство не дают никаких гарантий относительно того, увидит ли итератор изменения, сделанные во время итерации. (Я подозреваю, что это , в основном , потому что они также поточно-ориентированы, но я редко видел документированные гарантии того, что произойдет, если вы измените коллекцию в итерирующем потоке.)

РЕДАКТИРОВАТЬ: Я не уверен, что итератор является правильным подходом здесь. Вместо этого вы можете использовать:

while (!queue.isEmpty())
{
    // Put logic in here - add, poll etc
}

Следует отметить, что ваш опубликованный код фактически не перемещает итератор вперед - он никогда не вызывает it.next(). Это сильное предположение, что либо вы не используете итератор полностью, либо он вам вообще не нужен.

0 голосов
/ 12 мая 2010

Вы должны использовать ListIterator. Он имеет методы .remove () и .set (), которые позволят вам изменять базовую коллекцию, не теряя состояния итератора.

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

0 голосов
/ 11 мая 2010

Если 'queue' - это список, вы можете использовать ListIterator

выдержка:

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

0 голосов
/ 11 мая 2010

Это действительно скопированный твой код?

Я могу подумать, что Вы подтвердили, что q и queue являются ссылками на один и тот же объект очереди.
Таким образом, вы не можете изменять любой тип списка, очереди, стека при итерации по нему. Чтобы избежать итерации, вы можете попробовать цикл for(int i = 0; ..... ; i++). Но это не очень хорошая идея. Потому что вы меняете размер, когда используете размер, чтобы проверить, находитесь ли вы в конце цикла.


Я прочитал вашу правку:

for (int i = 0; i < 3;)
{
    boolean b = Math.random() < 0.5d;
    if (b)
    {
         queue.poll();
    } else {
         queue.add("new"); // or put(), I don't know exectly
         i++;  
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...