CopyOnWriteArrayList is a thread-safe variant of the ArrayList in which all mutative operations (add, set, etc.) are implemented by making a new copy of the underlying array. It belongs to the java.util.concurrent package and is designed for scenarios where iteration far more frequently happens than modification.

Key Points:

Thread-Safety: Designed to provide a way to iterate over the list in a thread-safe manner without external synchronization.

Performance Trade-off: Due to its copy-on-write nature, it’s efficient for cases where iterations outnumber modifications. However, it can be costly in scenarios where modifications are frequent since a copy of the array is created with every change.

Iteration Behavior: Iterators of this list never throw ConcurrentModificationException. Also, its iterators are guaranteed to see the state of the list at the time the iterator was created.

Null Elements: Like ArrayList, it allows null elements.

Common Methods of CopyOnWriteArrayList

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

public class CopyOnWriteArrayListDemo {
    public static void main(String[] args) {
        // 1. Initialization
        List<String> cowList = new CopyOnWriteArrayList<>();
        System.out.println("Initialized list: " + cowList);

        // 2. Adding elements
        cowList.add("Apple");
        cowList.add("Banana");
        cowList.add("Cherry");
        System.out.println("After adding elements: " + cowList);

        // 3. Remove an element
        cowList.remove("Banana");
        System.out.println("After removing Banana: " + cowList);

        // 4. Iterate over the list
        Iterator<String> iterator = cowList.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        // 5. Add element during iteration
        for (String item : cowList) {
            if ("Apple".equals(item)) {
                cowList.add("Dragonfruit");
            }
            System.out.println(item);
        }

        System.out.println("After adding Dragonfruit during iteration: " + cowList);
    }
}

Output:

Initialized list: []
After adding elements: [Apple, Banana, Cherry]
After removing Banana: [Apple, Cherry]
Apple
Cherry
Apple
Cherry
After adding Dragonfruit during iteration: [Apple, Cherry, Dragonfruit]

Explanation:

1. An empty CopyOnWriteArrayList of type String is initialized.

2. Elements are added to the list using the add method.

3. The remove method is used to delete the string "Banana" from the list.

4. The Iterator is used to traverse and print each element of the list.

5. The special feature of CopyOnWriteArrayList is demonstrated: it allows modifications like add during iteration without ConcurrentModificationException. As we iterate through the list, we add "Dragonfruit" when we encounter "Apple".

Real-World Example: Student Management with CopyOnWriteArrayList

Imagine you’re managing student records, and you need a system that allows multiple threads to safely iterate through student data while also supporting occasional modifications.

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

class Student {
    private String name;
    private int rollNo;

    public Student(String name, int rollNo) {
        this.name = name;
        this.rollNo = rollNo;
    }

    @Override
    public String toString() {
        return "Roll No: " + rollNo + ", Name: " + name;
    }
}

public class StudentManagement {
    public static void main(String[] args) {
        // 1. Initialization
        List<Student> studentList = new CopyOnWriteArrayList<>();
        System.out.println("Initialized student records: " + studentList);

        // 2. Adding students
        studentList.add(new Student("John Doe", 101));
        studentList.add(new Student("Jane Smith", 102));
        studentList.add(new Student("Sam Brown", 103));
        System.out.println("After adding students: " + studentList);

        // 3. Iterate and add new student during iteration
        for (Student student : studentList) {
            System.out.println(student);
            if (student.toString().contains("Jane Smith")) {
                studentList.add(new Student("Emma White", 104));
            }
        }

        System.out.println("After adding student during iteration: " + studentList);
    }
}

Output:

Initialized student records: []
After adding students: [Roll No: 101, Name: John Doe, Roll No: 102, Name: Jane Smith, Roll No: 103, Name: Sam Brown]
Roll No: 101, Name: John Doe
Roll No: 102, Name: Jane Smith
Roll No: 103, Name: Sam Brown
After adding student during iteration: [Roll No: 101, Name: John Doe, Roll No: 102, Name: Jane Smith, Roll No: 103, Name: Sam Brown, Roll No: 104, Name: Emma White]

Explanation:

1. An empty CopyOnWriteArrayList of type Student is initialized to store student records.

2. Students are added to the list using the add method.

3. As we iterate through the student records, we add a new student named "Emma White" when we encounter "Jane Smith".

4. The special feature of CopyOnWriteArrayList is highlighted here: it allows adding elements during iteration without throwing a ConcurrentModificationException.