I’m trying to make use of the foreach loop with the arraylist, but when I use it, it gives me error, but when I use normal for loop, it works perfectly, what could be the problem?
The code is here:
for (Pair p2 : R) {
if ((p2.getFirstElm() == p.getSecondElm()) && (p2.getFirstElm() != p2.getSecondElm()))
R.add(new Pair (p.getFirstElm(), p2.getSecondElm()));
else if ((p2.getSecondElm() == p.getFirstElm()) && (p2.getFirstElm() != p2.getSecondElm()))
R.add(new Pair (p2.getFirstElm(), p.getSecondElm()));
// else
// There are no transitive pairs in R.
}
this is the loop that doesnt work, and here is the one that works:
for (int i = 0; i < R.size(); i++) {
if ((R.get(i).getFirstElm() == p.getSecondElm()) && (R.get(i).getFirstElm() != R.get(i).getSecondElm()))
R.add(new Pair (p.getFirstElm(), R.get(i).getSecondElm()));
else if ((R.get(i).getSecondElm() == p.getFirstElm()) && (R.get(i).getFirstElm() != R.get(i).getSecondElm()))
R.add(new Pair (R.get(i).getFirstElm(), p.getSecondElm()));
//else
// There are no transitive pairs in R.
}
the error I’m getting when using the foreach loop is:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at set.problem.fourth.PoSet.makeTransitive(PoSet.java:145)
at set.problem.fourth.PoSet.addToR(PoSet.java:87)
at set.problem.fourth.PoSetDriver.typicalTesting(PoSetDriver.java:35)
at set.problem.fourth.PoSetDriver.main(PoSetDriver.java:13)
You can’t modify a
Listin afor/eachloop, which is syntactic sugar around theIteratoras an implementation detail. You can only safely call.remove()when using theIteratordirectly.Calling
.add()inside thefor/eachloop modifies the contents, and theIteratorthat is used behind the scenes sees this and throws this exception.A more subtle concern is the that the second way you list, the
.size()is increasing every time you.add()so you will end up processing all the things you.add(), this could possibly cause an endless loop depending on what the input data is. I am not sure if this is what you desire.Solution
I would create another
ArrayListand.add()to it all the new things, and then after the loop, use.addAll()on the originalArrayListto combine the two lists together. This will make things explicit in what you are trying to do, that is unless your intention is process all the newly added things as you add them.2014 Solution:
Always use
Immutablecollections classes and build newImmutablecollection classes instead of trying to modify a single shared one. This is basically what my 2012 answer says but I wanted to make it more explicit.Guava supports this very well, use
ImmutableList.copyOf()to pass around data.Use
Iterables.filter()to filter out stuff into a newImmutableList, no shared mutable state, means no concurrency problems!