Criteria CopyOnWriteArrayList ArrayList
Thread Safety Thread-safe. All mutative operations (add, set, remove, etc.) are implemented by making a fresh copy of the underlying array. Not thread-safe.
Performance Read operations are fast and without locking, but writes are relatively slow due to copying. Read and write operations are generally faster, but concurrency issues may arise in multi-threaded scenarios.
Memory Overhead Higher overhead because a new array is created with every modification. Lower overhead, as it uses a single array that resizes when necessary.
Iterator Behavior Iterators of this list will never throw ConcurrentModificationException. They also reflect the state of the list at the time the iterator was created. Iterators can throw ConcurrentModificationException if the list is modified while it’s being iterated over.
Use-case Useful in scenarios where read operations greatly outnumber write operations and thread-safety is required. Commonly used for lists that do not require synchronization.
Null Elements Allows null elements. Allows null elements.
Implementation Backed by an array that gets replaced on each modification. Backed by a dynamic array that can grow as needed.

Example: Difference Between CopyOnWriteArrayList and ArrayList in Java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListVsArrayListDemo {

    public static void main(String[] args) {
        // Using an ArrayList
        List<String> arrayList = new ArrayList<>();
        arrayList.add("Element1");
        arrayList.add("Element2");

        // Using a CopyOnWriteArrayList
        List<String> cowArrayList = new CopyOnWriteArrayList<>();
        cowArrayList.add("Element1");
        cowArrayList.add("Element2");

        // Modify ArrayList while iterating (will throw exception)
        try {
            Iterator<String> it = arrayList.iterator();
            while (it.hasNext()) {
                System.out.println(it.next());
                arrayList.add("NewElement");
            }
        } catch (Exception e) {
            System.out.println("Caught exception: " + e.getClass().getSimpleName());
        }

        // Modify CopyOnWriteArrayList while iterating (will not throw exception)
        Iterator<String> cowIt = cowArrayList.iterator();
        while (cowIt.hasNext()) {
            System.out.println(cowIt.next());
            cowArrayList.add("NewElement");
        }
        System.out.println("CopyOnWriteArrayList size after modification: " + cowArrayList.size());
    }
}

Output:

Element1
Element2
Caught exception: ConcurrentModificationException
Element1
Element2
CopyOnWriteArrayList size after modification: 4

Explanation:

1. ArrayList: It is not thread-safe. When you modify the list (add, remove elements) while iterating over it using an iterator, it will throw a ConcurrentModificationException.

2. CopyOnWriteArrayList: It is a thread-safe variant of ArrayList. When the list is modified, a new copy of the underlying array is created. This means that iterators on a CopyOnWriteArrayList never see the changes and will never throw a ConcurrentModificationException. However, due to this behavior, it's not efficient for lists that are frequently modified.

3. In the provided example:

– We first create an ArrayList and add two elements to it. When we try to modify the list (by adding a new element) while iterating over it, it throws a ConcurrentModificationException.- Next, we create a CopyOnWriteArrayList and add two elements to it. We then modify the list (by adding new elements) while iterating over it. It doesn't throw any exception and the new elements are added successfully, increasing its size to 4.

4. The CopyOnWriteArrayList class is useful in scenarios where write operations are infrequent and iteration is a more common operation, ensuring that there are no concurrent modification exceptions.