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

匿名 (未验证) 提交于 2019-12-03 01:09:02

问题:

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 nth23.experimental.MoveBetweenSets.main(MoveBetweenSets.java:25)

How can I get around this?

回答1:

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);


回答2:

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).



回答3:

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.



回答4:

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 :)



回答5:

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.



回答6:

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.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!