Let’s look into below example code. The only difference between these blocks is type of iteration. Example 1 uses Iterator and Example 2 uses for each loop.
package com.bruiser.java;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class CopyOnWriteArrayListDemo {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Banana");
fruits.add("Apple");
fruits.add("Orange");
Iterator<String> iterator= fruits.iterator();
while(iterator.hasNext()) {
String fruit = iterator.next();
if(fruit.equalsIgnoreCase("Orange")) {
fruits.remove("Orange");
}
}
}
}
package com.bruiser.java;
import java.util.ArrayList;
import java.util.List;
public class CopyOnWriteArrayListDemo {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Banana");
fruits.add("Apple");
fruits.add("Orange");
for(String fruit : fruits) {
if(fruit.equalsIgnoreCase("Orange")) {
fruits.remove("Orange");
}
}
}
}
Running either of above example will result in below exception.
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at com.bruiser.java.CopyOnWriteArrayListDemo.main(CopyOnWriteArrayListDemo.java:15)
So, what this exemption conveys us ? We are not allowed to modify the list during iteration. We resolve this exception by tweaking the code as below,
package com.bruiser.java;
import java.util.ArrayList;
import java.util.List;
public class CopyOnWriteArrayListDemo {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Banana");
fruits.add("Apple");
fruits.add("Orange");
List<String> copyOfFruits = new ArrayList<>();
copyOfFruits.addAll(fruits);
for(String fruit : fruits) {
if(fruit.equalsIgnoreCase("Orange")) {
copyOfFruits.remove(fruit);
}
}
for(String fruit : copyOfFruits) {
System.out.println(fruit);
}
}
}
Banana
Apple
Here is action of CopyOnWriteArrayList comes into the picture. It performs the same function as above tweaked code. As per java docs, CopyOnWriteArryList is “A thread-safe variant of ArrayList
in which all mutative operations (add
, set
, and so on) are implemented by making a fresh copy of the underlying array.”
Here is the example of using CopyOnWriteArrayList,
package com.bruiser.java;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListDemo {
public static void main(String[] args) {
List<String> fruits = new CopyOnWriteArrayList<>();
fruits.add("Banana");
fruits.add("Apple");
fruits.add("Orange");
for(String fruit : fruits) {
if(fruit.equalsIgnoreCase("Orange")) {
fruits.remove(fruit);
}
}
for(String fruit : fruits) {
System.out.println(fruit);
}
}
}
Banana
Apple