views:

205

answers:

5

This is my code:

Iterator it = queue.iterator();

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

It gives me:

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)

Edit @Jon Skeet:

What I want to do is:

  • I have a queue list in, let say the size is 10, lets say: a,b,c,d ... j
  • Generate a number between 1 and 2. if 1, pull (remove the top element) else if 2 add new element
  • I will stop the loop until I added 3 new elements
+1  A: 

In general, you can't modify collections while you're iterating over them. One alternative is to build a separate list of "changes" you want to apply, and then apply them once you've finished iterating.

Alternatively, some collections do support this such as ConcurrentLinkedQueue - but most offer no guarantees about whether the iterator will see the changes made while you're iterating. (I suspect that's mainly because they're also thread-safe, but I've rarely seen documented guarantees about what will happen if you modify the collection within the iterating thread.)

EDIT: I'm not sure that an iterator is the right approach here. Instead, you could use:

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

One thing to note is that your posted code doesn't actually move the iterator forward at any time - it never calls it.next(). That's a strong suggestion that either you're not using the iterator fully, or you don't need it at all.

Jon Skeet
Hmm.. cant do it while iterate... :(I dont get you alternative way. Can give some examples?
javaLearner.java
@javaLearner: It really depends on what you want to achieve - what's your actual goal here? Do you need your iterator to "see" the additional items you're adding?
Jon Skeet
Is there any way to throw the ConcurrentModificationException?
javaLearner.java
@javaLearner: I'm not sure what you mean. Why would you *want* to throw it yourself?
Jon Skeet
I will try your "while" loop method, see if it works.
javaLearner.java
wait.. while(!queue.isEmpty()), it might give me infinite loop, isnt it??
javaLearner.java
Shaded
@javaLearner The idea is to remove elements within the loop until the collection is emtpy.
Helper Method
A: 

Is this really copy-pasted your code?

What I can think is that You confirmed that q and queue are references to the same queue-object.
So you cannot modify any type of list, queue, stack when iterating over it. To avoid iteration, you can try a for(int i = 0; ..... ; i++) loop. But this isn't a good idea. Because you are changing size when you are using the size to check if you are at the end of the loop.


I read your edit:

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++;  
    }
}
Martijn Courteaux
Yes, its my very original code. I copy paste my code, then edit it(include variable name), but the flow is the same.
javaLearner.java
@Martin: I tried using "for" loop, it does not help =(
javaLearner.java
I mean, i copy paste my code and modify the variable name. I am 100% confirm that the "q" and "queue" are references to the same queue object.
javaLearner.java
A: 

If 'queue' is a List, you can use ListIterator

excerpt:

An iterator for lists that allows the programmer to traverse the list in either direction, modify the list during iteration, and obtain the iterator's current position in the list.

Mihir Mathuria
A: 

I'm guessing a bit at what you want to do, but it looks like sometimes adding an element, followed by always polling an element, and then stopping when the poll returns nothing. To do that, I might do something like

while( maybeAddAlwaysPoll(1,2,queue) );

with method elsewhere

private boolean maybeAddAlwaysPoll(int one, int two, Queue<String> queue) {
   if (randNumber(one,two)!=1) queue.add("new");
   return queue.poll()!=null;
}

this is essentially Jon's answer, with the activity of the while baked into the method call. Perhaps that idiom is unattractive to some, but I find it understandable with good-naming, and flexible when implemented with a side-effecting Predicate.

Carl
A: 

You should use ListIterator. It has .remove() and .set() methods that will allow you to modify the underlying collection without hosing the iterator's state.

In general, modifying the collection in any other way is going to hose the iterator's state--be glad it threw an exception and didn't do something more insidious.

Bill K