Reputation: 4655
I'm currently having problems with the following, using Java 8:
I want to pass an ArrayList<String>
as argument to another method. This method, among other things, removes an object from the ArrayList it was given:
public static void calledMethod(String item, ArrayList<String> list) {
list.remove(item);
}
Now I tried calling this method like this from main:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next(); //<-
calledMethod(item, list);
}
In this case, the JVM returns a java.util.ConcurrentModificationException at the marked line in the code above (//<-
). As far as my knowledge goes, this means that the list was modified while it was iterated. But how can this happen? As far as I know, Java hands method arguments by value, not by reference. If I call calledMethod
using the following code in my main method, no error occurs:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next(); //<-
calledMethod(item, (ArrayList<String>) list.clone());
}
So passing a cloned object to calledMethod
works. What is wrong here?
java -version
: Java SE Runtime Environment (build 1.8.0_20-b26)
I'm using Oracle Java on a Linux Mint 64bit.
Upvotes: 0
Views: 237
Reputation: 2404
What happens here is that your iterator got "lost" due to "concurrent" modification on the list (it's not actually concurrent, but it's a modification made on the list without notifying the iterator. So from Iterator point of view, it's as if the list was modified at the same time)
While iterating through a list, you should never remove an element with List.remove. Use Iterator.remove instead, this way the iterator won't have an invalid state due to removing:
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next();
itr.remove(); // will remove "item" and keep iterator in a correct state
}
Upvotes: 1
Reputation: 1629
Yes you pass it by value, but you are passing an object which is actually passing the reference of the object in that case. Thus you are still modifying the actualy list in the calledMethod.
Upvotes: 0
Reputation: 178253
Yes, Java is pass by value. But what is list
? It's a reference to the actual ArrayList
object. When it's passed to the method, it's copied, but the copy still refers to the same object, so the method's modification is visible to the calling method, and a ConcurrentModificationException
occurs.
When you clone the object, only then is a copy of the object made, preventing the ConcurrentModificationException
.
Upvotes: 5