Java CopyOnWriteArrayList Tutorial with Examples

CopyOnWriteArrayList is a thread-safe variant of ArrayList in the Java Collections Framework. It is designed for cases where read operations vastly outnumber write operations. This tutorial will cover all methods of CopyOnWriteArrayList with examples and outputs, highlighting key points, use cases, best practices, performance considerations, and a real-time example with CRUD operations.

Table of Contents

  1. Introduction
  2. Key Points
  3. CopyOnWriteArrayList Methods
    • add()
    • addAll()
    • get()
    • set()
    • remove()
    • clear()
    • size()
    • isEmpty()
    • contains()
    • indexOf()
    • lastIndexOf()
    • toArray()
    • iterator()
    • listIterator()
    • subList()
  4. Use Cases
  5. Best Practices
  6. Performance Considerations
  7. Real-time Example with CRUD Operations
  8. Conclusion

1. Introduction

CopyOnWriteArrayList is a part of the java.util.concurrent package and is designed to provide thread-safe operations for scenarios where the list is frequently read and occasionally modified. It creates a fresh copy of the underlying array for each write operation, ensuring thread safety without the need for synchronization.

2. Key Points

  • CopyOnWriteArrayList is best suited for situations where read operations are much more frequent than write operations.
  • It provides thread safety without the need for external synchronization.
  • Modifications (add, set, remove) result in a new copy of the list, which can be resource-intensive for frequent updates.
  • Iterators returned by CopyOnWriteArrayList do not support remove operations.

3. CopyOnWriteArrayList Methods

3.1. add()

The add() method inserts elements into the CopyOnWriteArrayList.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        System.out.println(animals);
    }
}

Output:

[Lion, Tiger, Elephant]

3.2. addAll()

The addAll() method adds all elements of a collection to the CopyOnWriteArrayList.

Example:

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Arrays;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.addAll(Arrays.asList("Tiger", "Elephant"));
        System.out.println(animals);
    }
}

Output:

[Lion, Tiger, Elephant]

3.3. get()

The get() method returns the element at the specified index.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        System.out.println(animals.get(1)); // Tiger
    }
}

Output:

Tiger

3.4. set()

The set() method updates the element at the specified index.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        animals.set(1, "Panther");
        System.out.println(animals);
    }
}

Output:

[Lion, Panther, Elephant]

3.5. remove()

The remove() method removes the element at the specified index or the first occurrence of the specified element.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        animals.remove(1);
        System.out.println(animals); // [Lion, Elephant]

        animals.remove("Elephant");
        System.out.println(animals); // [Lion]
    }
}

Output:

[Lion, Elephant]
[Lion]

3.6. clear()

The clear() method removes all elements from the CopyOnWriteArrayList.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        animals.clear();
        System.out.println(animals);
    }
}

Output:

[]

3.7. size()

The size() method returns the number of elements in the CopyOnWriteArrayList.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        System.out.println(animals.size()); // 3
    }
}

Output:

3

3.8. isEmpty()

The isEmpty() method checks if the CopyOnWriteArrayList is empty.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        System.out.println(animals.isEmpty()); // true
        animals.add("Lion");
        System.out.println(animals.isEmpty()); // false
    }
}

Output:

true
false

3.9. contains()

The contains() method checks if the CopyOnWriteArrayList contains a specified element.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        System.out.println(animals.contains("Tiger")); // true
        System.out.println(animals.contains("Elephant")); // false
    }
}

Output:

true
false

3.10. indexOf()

The indexOf() method returns the index of the first occurrence of the specified element.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Lion");
        System.out.println(animals.indexOf("Lion")); // 0
    }
}

Output:

0

3.11. lastIndexOf()

The lastIndexOf() method returns the index of the last occurrence of the specified element.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Lion");
        System.out.println(animals.lastIndexOf("Lion")); // 2
    }
}

Output:

2

3.12. toArray()

The toArray() method converts the CopyOnWriteArrayList into an array.

Example:

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        String[] animalsArray = animals.toArray(new String[0]);
        for (String animal : animalsArray) {
            System.out.println(animal);
        }
    }
}

Output:

Lion
Tiger
Elephant

3.13. iterator()

The iterator() method returns an iterator for the elements in the CopyOnWriteArrayList.

Example:

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

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new

 CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        Iterator<String> iterator = animals.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

Output:

Lion
Tiger
Elephant

3.14. listIterator()

The listIterator() method returns a list iterator for the elements in the CopyOnWriteArrayList.

Example:

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.ListIterator;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        ListIterator<String> listIterator = animals.listIterator();
        while (listIterator.hasNext()) {
            System.out.println(listIterator.next());
        }
        while (listIterator.hasPrevious()) {
            System.out.println(listIterator.previous());
        }
    }
}

Output:

Lion
Tiger
Elephant
Elephant
Tiger
Lion

3.15. subList()

The subList() method returns a view of the portion of the CopyOnWriteArrayList between the specified indices.

Example:

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

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> animals = new CopyOnWriteArrayList<>();
        animals.add("Lion");
        animals.add("Tiger");
        animals.add("Elephant");
        animals.add("Panther");
        List<String> subList = animals.subList(1, 3);
        System.out.println(subList);
    }
}

Output:

[Tiger, Elephant]

4. Use Cases

  • Thread-safe lists: CopyOnWriteArrayList is used when multiple threads need to access a list concurrently.
  • Read-heavy scenarios: It is ideal for situations where read operations vastly outnumber write operations.
  • Immutability: It can be used when a snapshot of the list is needed, as it guarantees that the list won't change during iteration.

5. Best Practices

  • Minimize writes: Since CopyOnWriteArrayList creates a new copy of the array on each write, keep write operations to a minimum.
  • Use for read-heavy tasks: It is best suited for scenarios where read operations are significantly more frequent than write operations.
  • Avoid using in write-heavy applications: Due to the overhead of copying the array on each write, it should be avoided in write-heavy applications.

6. Performance Considerations

  • Read performance: Read operations are very fast as they do not require locking.
  • Write performance: Write operations can be costly due to the need to create a new copy of the array.
  • Memory usage: Each modification results in a new copy of the array, which can lead to increased memory usage.

7. Real-time Example with CRUD Operations

Managing a Fruit Inventory:

Fruit.java:

public class Fruit {
    private String name;
    private int quantity;

    public Fruit(String name, int quantity) {
        this.name = name;
        this.quantity = quantity;
    }

    public String getName() {
        return name;
    }

    public int getQuantity() {
        return quantity;
    }

    @Override
    public String toString() {
        return "Fruit{name='" + name + "', quantity=" + quantity + "}";
    }
}

Main.java:

import java.util.concurrent.CopyOnWriteArrayList;

public class Main {
    public static void main(String[] args) {
        CopyOnWriteArrayList<Fruit> fruitInventory = new CopyOnWriteArrayList<>();

        // Create
        fruitInventory.add(new Fruit("Apple", 50));
        fruitInventory.add(new Fruit("Banana", 30));
        fruitInventory.add(new Fruit("Mango", 20));

        // Read
        for (Fruit fruit : fruitInventory) {
            System.out.println(fruit);
        }

        // Update
        fruitInventory.set(1, new Fruit("Banana", 40));
        System.out.println("After Update:");
        for (Fruit fruit : fruitInventory) {
            System.out.println(fruit);
        }

        // Delete
        fruitInventory.remove(0);
        System.out.println("After Deletion:");
        for (Fruit fruit : fruitInventory) {
            System.out.println(fruit);
        }
    }
}

Output:

Fruit{name='Apple', quantity=50}
Fruit{name='Banana', quantity=30}
Fruit{name='Mango', quantity=20}
After Update:
Fruit{name='Apple', quantity=50}
Fruit{name='Banana', quantity=40}
Fruit{name='Mango', quantity=20}
After Deletion:
Fruit{name='Banana', quantity=40}
Fruit{name='Mango', quantity=20}

8. Conclusion

The CopyOnWriteArrayList class in Java is a powerful tool for managing thread-safe lists, especially in read-heavy scenarios. By understanding its methods, use cases, and best practices, you can effectively utilize CopyOnWriteArrayList in your Java applications. This tutorial covers the essential methods with examples and demonstrates a real-time example with CRUD operations.

Comments