开发者

Java: Changing the properties of an iterable object while iterating over it

The following code is just to produce an example of the problem:

 public static void main(String[] args) {
  Collection<Integer> src = new ArrayList<Integer>();
  Collection<Integer> dest = new ArrayList<Integer>();

  src.add(2);
  src.add(7);
  src.add(3);
  src.add(2201);
  src.add(-21);

  dest.add(10);

  while (src.size() != 0) {
   for (int i : dest) {
    int min = Collections.min(src);
    dest.add(min);
    src.remove(min);
   }
  }

 }

What I want to do is move everything from src to dest in a specific order. (Here, it's what is the minimum value, but that's just a simplification from my real problem.) However, I am modifying dest while iterating over it, and get the following error:

Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
 at java.util.AbstractList$Itr.next(Unknown Source)
 at nth开发者_JAVA百科23.experimental.MoveBetweenSets.main(MoveBetweenSets.java:25)

How can I get around this?


Is there a reason why you can't just copy the source list to the destination list and then sort it?

Collection<Integer> dest = new ArrayList<Integer>(src);
Collections.sort(dest);


This is a workaround:

while (!src.isEmpty()) {
    int min = Collections.min(src);
    dest.add(min);
    src.remove(min);
}

But this might be even make thing worse. Be a bit more specific (as Jon mentioned).


You can remove from a collection (well, some collections) while iterating over it using iterator.remove() - but you can't usually add to it.

However, as newacct points out in comments, the ListIterator interface does include an add method, so you should be able to change your code like this:

public static void main(String[] args) {
  Collection<Integer> src = new ArrayList<Integer>();
  List<Integer> dest = new ArrayList<Integer>();

  src.add(2);
  src.add(7);
  src.add(3);
  src.add(2201);
  src.add(-21);

  dest.add(10);

  while (src.size() != 0) {
   for (ListIterator<Integer> li = dest.listIterator(); li.hasNext() ;) {
    int min = Collections.min(src);
    li.add(min);
    src.remove(min);
   }
  } 
 }

Note that now dest has to be declared as List rather than Collection, and you need to expand the for loop explicitly. However, I'm still not sure why you're iterating over dest in the first place. You're adding an element on every iteration, so you'll never reach the end.

What's wrong with this?

  while (src.size() != 0) {
    int min = Collections.min(src);
    dest.add(min);
    src.remove(min);
  } 

Or, as others have said, just call sort() - passing in a custom Comparator if you need to.


To be honest, I don't get the for (int i : dest) part. And if you remove it, there is actually no problem and this answers the question :)


As you've seen, you cannot change a collection while you iterate over it. (To be more precise, you can change it, but you can't continue iterating)

You can either iterate over a copy of the list or use a traditional for loop.

Either way, make sure that you understand exactly what happens to the indices as you modify the collection; otherwise, your code won't work correctly.

For more specific advice, tell us what you're actually doing.


You could create temporary lists where you keep track of what should be added and removed without actually making changes to dest and src. Then, outside of the loop use the temporary lists to add and remove necessary items. But like Jon Skeet said, more specific requirements would help. I assume there are some limitations.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜