Mega Code Archive

 
Categories / Java / Collections Data Structure
 

A variant of java util ArrayList in which all mutative operations (add, set, and so on) are implemented by maki

/*  * File: CopyOnWriteArrayList.java  *   * Written by Doug Lea. Adapted and released, under explicit permission, from  * JDK1.2 ArrayList.java which carries the following copyright:  *   * Copyright 1997 by Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto,  * California, 94303, U.S.A. All rights reserved.  *   * This software is the confidential and proprietary information of Sun  * Microsystems, Inc. ("Confidential Information"). You shall not disclose such  * Confidential Information and shall use it only in accordance with the terms  * of the license agreement you entered into with Sun.  *   * History: Date Who What 21Jun1998 dl Create public version 9Oct1999 dl faster  * equals 29jun2001 dl Serialization methods now private  */ import java.util.*; /**  * This class implements a variant of java.util.ArrayList in which all mutative  * operations (add, set, and so on) are implemented by making a fresh copy of  * the underlying array.  * <p>  * This is ordinarily too costly, but it becomes attractive when traversal  * operations vastly overwhelm mutations, and, especially, when you cannot or  * don't want to synchronize traversals, yet need to preclude interference among  * concurrent threads. The iterator method uses a reference to the state of the  * array at the point that the iterator was created. This array never changes  * during the lifetime of the iterator, so interference is impossible. (The  * iterator will not traverse elements added or changed since the iterator was  * created, but usually this is a desirable feature.)  * <p>  * As much code and documentation as possible was shamelessly copied from  * java.util.ArrayList (Thanks, Josh!), with the intent of preserving all  * semantics of ArrayList except for the copy-on-write property. (The java.util  * collection code could not be subclassed here since all of the existing  * collection classes assume elementwise mutability.)  * <p>  * Because of the copy-on-write policy, some one-by-one mutative operations in  * the java.util.Arrays and java.util.Collections classes are so time/space  * intensive as to never be worth calling (except perhaps as benchmarks for  * garbage collectors :-).  * <p>  * Three methods are supported in addition to those described in List and  * ArrayList. The addIfAbsent and addAllAbsent methods provide Set semantics for  * add, and are used in CopyOnWriteArraySet. However, they can also be used  * directly from this List version. The copyIn method (and a constructor that  * invokes it) allow you to copy in an initial array to use. This method can be  * useful when you first want to perform many operations on a plain array, and  * then make a copy available for use through the collection API.  * <p>  * Due to their strict read-only nature, element-changing operations on  * iterators (remove, set, and add) are not supported. These are the only  * methods throwing UnsupportedOperationException.  * <p>  * <p>[<a  * href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html">  * Introduction to this package. </a>]  *   * @see CopyOnWriteArraySet  */ public class CopyOnWriteArrayList implements List, Cloneable, java.io.Serializable {   private static final long serialVersionUID = 1L;   /**    * The held array. Directly access only within synchronized methods    */   protected transient Object[] array_;   /**    * Accessor to the array intended to be called from within unsynchronized    * read-only methods    *     * @return The internal array    */   protected synchronized Object[] array()   {     return array_;   }   /**    * Constructs an empty list    *     */   public CopyOnWriteArrayList()   {     array_ = new Object[0];   }   /**    * Constructs an list containing the elements of the specified Collection,    * in the order they are returned by the Collection's iterator.    *     * @param c The collection to get the objects from.     */   public CopyOnWriteArrayList(Collection c)   {     array_ = new Object[c.size()];     Iterator i = c.iterator();     int size = 0;     while (i.hasNext())       array_[size++] = i.next();   }   /**    * Create a new CopyOnWriteArrayList holding a copy of given array    *     * @param toCopyIn    *            the array. A copy of this array is used as the internal array.    */   public CopyOnWriteArrayList(Object[] toCopyIn)   {     copyIn(toCopyIn, 0, toCopyIn.length);   }   /**    * Replace the held array with a copy of the <code>n</code> elements of    * the provided array, starting at position <code>first</code>. To copy    * an entire array, call with arguments (array, 0, array.length).    *     * @param toCopyIn    *            the array. A copy of the indicated elements of this array is    *            used as the internal array.    * @param first    *            The index of first position of the array to start copying    *            from.    * @param n    *            the number of elements to copy. This will be the new size of    *            the list.    */   public synchronized void copyIn(Object[] toCopyIn, int first, int n)   {     array_ = new Object[n];     System.arraycopy(toCopyIn, first, array_, 0, n);   }   /**    * Returns the number of components in this list.    *     * @return the number of components in this list.    */   public int size()   {     return array().length;   }   /**    * Tests if this list has no components.    *     * @return <code>true</code> if this list has no components;    *         <code>false</code> otherwise.    */   public boolean isEmpty()   {     return size() == 0;   }   /**    * Returns true if this list contains the specified element.    *     * @param o    *            element whose presence in this List is to be tested.    */   public boolean contains(Object elem)   {     Object[] elementData = array();     int len = elementData.length;     return indexOf(elem, elementData, len) >= 0;   }   /**    * Searches for the first occurence of the given argument, testing for    * equality using the <code>equals</code> method.    *     * @param elem    *            an object.    * @return the index of the first occurrence of the argument in this list;    *         returns <code>-1</code> if the object is not found.    * @see Object#equals(Object)    */   public int indexOf(Object elem)   {     Object[] elementData = array();     int len = elementData.length;     return indexOf(elem, elementData, len);   }   /**    * static version allows repeated call without needed to grab lock for array    * each time    * @param elem     * @param elementData     * @param len     * @return The index that is found. -1 if not found    */   protected static int indexOf(Object elem, Object[] elementData, int len)   {     if (elem == null)     {       for (int i = 0; i < len; i++)         if (elementData[i] == null)           return i;     }     else     {       for (int i = 0; i < len; i++)         if (elem.equals(elementData[i]))           return i;     }     return -1;   }   /**    * Searches for the first occurence of the given argument, beginning the    * search at <code>index</code>, and testing for equality using the    * <code>equals</code> method.    *     * @param elem    *            an object.    * @param index    *            the index to start searching from.    * @return the index of the first occurrence of the object argument in this    *         List at position <code>index</code> or later in the List;    *         returns <code>-1</code> if the object is not found.    * @see Object#equals(Object)    */   // needed in order to compile on 1.2b3   public int indexOf(Object elem, int index)   {     Object[] elementData = array();     int elementCount = elementData.length;     if (elem == null)     {       for (int i = index; i < elementCount; i++)         if (elementData[i] == null)           return i;     }     else     {       for (int i = index; i < elementCount; i++)         if (elem.equals(elementData[i]))           return i;     }     return -1;   }   /**    * Returns the index of the last occurrence of the specified object in this    * list.    *     * @param elem    *            the desired component.    * @return the index of the last occurrence of the specified object in this    *         list; returns -1 if the object is not found.    */   public int lastIndexOf(Object elem)   {     Object[] elementData = array();     int len = elementData.length;     return lastIndexOf(elem, elementData, len);   }   protected static int lastIndexOf(Object elem, Object[] elementData, int len)   {     if (elem == null)     {       for (int i = len - 1; i >= 0; i--)         if (elementData[i] == null)           return i;     }     else     {       for (int i = len - 1; i >= 0; i--)         if (elem.equals(elementData[i]))           return i;     }     return -1;   }   /**    * Searches backwards for the specified object, starting from the specified    * index, and returns an index to it.    *     * @param elem    *            the desired component.    * @param index    *            the index to start searching from.    * @return the index of the last occurrence of the specified object in this    *         List at position less than index in the List; -1 if the object is    *         not found.    */   public int lastIndexOf(Object elem, int index)   {     // needed in order to compile on 1.2b3     Object[] elementData = array();     if (elem == null)     {       for (int i = index; i >= 0; i--)         if (elementData[i] == null)           return i;     }     else     {       for (int i = index; i >= 0; i--)         if (elem.equals(elementData[i]))           return i;     }     return -1;   }   /**    * Returns a shallow copy of this list. (The elements themselves are not    * copied.)    *     * @return a clone of this list.    */   public Object clone()   {     try     {       Object[] elementData = array();       CopyOnWriteArrayList v = (CopyOnWriteArrayList)super.clone();       v.array_ = new Object[elementData.length];       System.arraycopy(elementData, 0, v.array_, 0, elementData.length);       return v;     }     catch (CloneNotSupportedException e)     {       // this shouldn't happen, since we are Cloneable       throw new InternalError();     }   }   /**    * Returns an array containing all of the elements in this list in the    * correct order.    */   public Object[] toArray()   {     Object[] elementData = array();     Object[] result = new Object[elementData.length];     System.arraycopy(elementData, 0, result, 0, elementData.length);     return result;   }   /**    * Returns an array containing all of the elements in this list in the    * correct order. The runtime type of the returned array is that of the    * specified array. If the list fits in the specified array, it is returned    * therein. Otherwise, a new array is allocated with the runtime type of the    * specified array and the size of this list.    * <p>    * If the list fits in the specified array with room to spare (i.e., the    * array has more elements than the list), the element in the array    * immediately following the end of the collection is set to null. This is    * useful in determining the length of the list <em>only</em> if the    * caller knows that the list does not contain any null elements.    *     * @param a    *            the array into which the elements of the list are to be    *            stored, if it is big enough; otherwise, a new array of the    *            same runtime type is allocated for this purpose.    * @return an array containing the elements of the list.    * @exception ArrayStoreException    *                the runtime type of a is not a supertype of the runtime    *                type of every element in this list.    */   public Object[] toArray(Object a[])   {     Object[] elementData = array();     if (a.length < elementData.length)       a = (Object[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(),           elementData.length);     System.arraycopy(elementData, 0, a, 0, elementData.length);     if (a.length > elementData.length)       a[elementData.length] = null;     return a;   }   // Positional Access Operations   /**    * Returns the element at the specified position in this list.    *     * @param index    *            index of element to return.    * @exception IndexOutOfBoundsException    *                index is out of range (index &lt; 0 || index &gt;=    *                size()).    */   public Object get(int index)   {     Object[] elementData = array();     rangeCheck(index, elementData.length);     return elementData[index];   }   /**    * Replaces the element at the specified position in this list with the    * specified element.    *     * @param index    *            index of element to replace.    * @param element    *            element to be stored at the specified position.    * @return the element previously at the specified position.    * @exception IndexOutOfBoundsException    *                index out of range (index &lt; 0 || index &gt;= size()).    */   public synchronized Object set(int index, Object element)   {     int len = array_.length;     rangeCheck(index, len);     Object oldValue = array_[index];     boolean same = (oldValue == element || (element != null && element.equals(oldValue)));     if (!same)     {       Object[] newArray = new Object[len];       System.arraycopy(array_, 0, newArray, 0, len);       newArray[index] = element;       array_ = newArray;     }     return oldValue;   }   /**    * Appends the specified element to the end of this list.    *     * @param element    *            element to be appended to this list.    * @return true (as per the general contract of Collection.add).    */   public synchronized boolean add(Object element)   {     int len = array_.length;     Object[] newArray = new Object[len + 1];     System.arraycopy(array_, 0, newArray, 0, len);     newArray[len] = element;     array_ = newArray;     return true;   }   /**    * Inserts the specified element at the specified position in this list.    * Shifts the element currently at that position (if any) and any subsequent    * elements to the right (adds one to their indices).    *     * @param index    *            index at which the specified element is to be inserted.    * @param element    *            element to be inserted.    * @exception IndexOutOfBoundsException    *                index is out of range (index &lt; 0 || index &gt; size()).    */   public synchronized void add(int index, Object element)   {     int len = array_.length;     if (index > len || index < 0)       throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + len);     Object[] newArray = new Object[len + 1];     System.arraycopy(array_, 0, newArray, 0, index);     newArray[index] = element;     System.arraycopy(array_, index, newArray, index + 1, len - index);     array_ = newArray;   }   /**    * Removes the element at the specified position in this list. Shifts any    * subsequent elements to the left (subtracts one from their indices).    * Returns the element that was removed from the list.    *     * @param index    *            the index of the element to removed.    * @exception IndexOutOfBoundsException    *                index out of range (index &lt; 0 || index &gt;= size()).    */   public synchronized Object remove(int index)   {     int len = array_.length;     rangeCheck(index, len);     Object oldValue = array_[index];     Object[] newArray = new Object[len - 1];     System.arraycopy(array_, 0, newArray, 0, index);     int numMoved = len - index - 1;     if (numMoved > 0)       System.arraycopy(array_, index + 1, newArray, index, numMoved);     array_ = newArray;     return oldValue;   }   /**    * Removes a single instance of the specified element from this Collection,    * if it is present (optional operation). More formally, removes an element    * <code>e</code> such that <code>(o==null ? e==null :    * o.equals(e))</code>,    * if the Collection contains one or more such elements. Returns true if the    * Collection contained the specified element (or equivalently, if the    * Collection changed as a result of the call).    *     * @param element    *            element to be removed from this Collection, if present.    * @return true if the Collection changed as a result of the call.    */   public synchronized boolean remove(Object element)   {     int len = array_.length;     if (len == 0)       return false;     // Copy while searching for element to remove     // This wins in the normal case of element being present     int newlen = len - 1;     Object[] newArray = new Object[newlen];     for (int i = 0; i < newlen; ++i)     {       if (element == array_[i] || (element != null && element.equals(array_[i])))       {         // found one; copy remaining and exit         for (int k = i + 1; k < len; ++k)           newArray[k - 1] = array_[k];         array_ = newArray;         return true;       }       else         newArray[i] = array_[i];     }     // special handling for last cell     if (element == array_[newlen] || (element != null && element.equals(array_[newlen])))     {       array_ = newArray;       return true;     }     else       return false; // throw away copy   }   /**    * Removes from this List all of the elements whose index is between    * fromIndex, inclusive and toIndex, exclusive. Shifts any succeeding    * elements to the left (reduces their index). This call shortens the List    * by (toIndex - fromIndex) elements. (If toIndex==fromIndex, this operation    * has no effect.)    *     * @param fromIndex    *            index of first element to be removed.    * @param toIndex    *            index after last element to be removed.    * @exception IndexOutOfBoundsException    *                fromIndex or toIndex out of range (fromIndex &lt; 0 ||    *                fromIndex &gt;= size() || toIndex &gt; size() || toIndex    *                &lt; fromIndex).    */   public synchronized void removeRange(int fromIndex, int toIndex)   {     int len = array_.length;     if (fromIndex < 0 || fromIndex >= len || toIndex > len || toIndex < fromIndex)       throw new IndexOutOfBoundsException();     int numMoved = len - toIndex;     int newlen = len - (toIndex - fromIndex);     Object[] newArray = new Object[newlen];     System.arraycopy(array_, 0, newArray, 0, fromIndex);     System.arraycopy(array_, toIndex, newArray, fromIndex, numMoved);     array_ = newArray;   }   /**    * Append the element if not present. This operation can be used to obtain    * Set semantics for lists.    *     * @param element    *            element to be added to this Collection, if absent.    * @return true if added    */   public synchronized boolean addIfAbsent(Object element)   {     // Copy while checking if already present.     // This wins in the most common case where it is not present     int len = array_.length;     Object[] newArray = new Object[len + 1];     for (int i = 0; i < len; ++i)     {       if (element == array_[i] || (element != null && element.equals(array_[i])))         return false; // exit, throwing away copy       else         newArray[i] = array_[i];     }     newArray[len] = element;     array_ = newArray;     return true;   }   /**    * Returns true if this Collection contains all of the elements in the    * specified Collection.    * <p>    * This implementation iterates over the specified Collection, checking each    * element returned by the Iterator in turn to see if it's contained in this    * Collection. If all elements are so contained true is returned, otherwise    * false.    *     */   public boolean containsAll(Collection c)   {     Object[] elementData = array();     int len = elementData.length;     Iterator e = c.iterator();     while (e.hasNext())       if (indexOf(e.next(), elementData, len) < 0)         return false;     return true;   }   /**    * Removes from this Collection all of its elements that are contained in    * the specified Collection. This is a particularly expensive operation in    * this class because of the need for an internal temporary array.    * <p>    *     * @return true if this Collection changed as a result of the call.    */   public synchronized boolean removeAll(Collection c)   {     Object[] elementData = array_;     int len = elementData.length;     if (len == 0)       return false;     // temp array holds those elements we know we want to keep     Object[] temp = new Object[len];     int newlen = 0;     for (int i = 0; i < len; ++i)     {       Object element = elementData[i];       if (!c.contains(element))       {         temp[newlen++] = element;       }     }     if (newlen == len)       return false;     // copy temp as new array     Object[] newArray = new Object[newlen];     System.arraycopy(temp, 0, newArray, 0, newlen);     array_ = newArray;     return true;   }   /**    * Retains only the elements in this Collection that are contained in the    * specified Collection (optional operation). In other words, removes from    * this Collection all of its elements that are not contained in the    * specified Collection.    *     * @return true if this Collection changed as a result of the call.    */   public synchronized boolean retainAll(Collection c)   {     Object[] elementData = array_;     int len = elementData.length;     if (len == 0)       return false;     Object[] temp = new Object[len];     int newlen = 0;     for (int i = 0; i < len; ++i)     {       Object element = elementData[i];       if (c.contains(element))       {         temp[newlen++] = element;       }     }     if (newlen == len)       return false;     Object[] newArray = new Object[newlen];     System.arraycopy(temp, 0, newArray, 0, newlen);     array_ = newArray;     return true;   }   /**    * Appends all of the elements in the specified Collection that are not    * already contained in this list, to the end of this list, in the order    * that they are returned by the specified Collection's Iterator.    *     * @param c    *            elements to be added into this list.    * @return the number of elements added    */   public synchronized int addAllAbsent(Collection c)   {     int numNew = c.size();     if (numNew == 0)       return 0;     Object[] elementData = array_;     int len = elementData.length;     Object[] temp = new Object[numNew];     int added = 0;     Iterator e = c.iterator();     while (e.hasNext())     {       Object element = e.next();       if (indexOf(element, elementData, len) < 0)       {         if (indexOf(element, temp, added) < 0)         {           temp[added++] = element;         }       }     }     if (added == 0)       return 0;     Object[] newArray = new Object[len + added];     System.arraycopy(elementData, 0, newArray, 0, len);     System.arraycopy(temp, 0, newArray, len, added);     array_ = newArray;     return added;   }   /**    * Removes all of the elements from this list.    *     */   public synchronized void clear()   {     array_ = new Object[0];   }   /**    * Appends all of the elements in the specified Collection to the end of    * this list, in the order that they are returned by the specified    * Collection's Iterator.    *     * @param c    *            elements to be inserted into this list.    */   public synchronized boolean addAll(Collection c)   {     int numNew = c.size();     if (numNew == 0)       return false;     int len = array_.length;     Object[] newArray = new Object[len + numNew];     System.arraycopy(array_, 0, newArray, 0, len);     Iterator e = c.iterator();     for (int i = 0; i < numNew; i++)       newArray[len++] = e.next();     array_ = newArray;     return true;   }   /**    * Inserts all of the elements in the specified Collection into this list,    * starting at the specified position. Shifts the element currently at that    * position (if any) and any subsequent elements to the right (increases    * their indices). The new elements will appear in the list in the order    * that they are returned by the specified Collection's iterator.    *     * @param index    *            index at which to insert first element from the specified    *            collection.    * @param c    *            elements to be inserted into this list.    * @exception IndexOutOfBoundsException    *                index out of range (index &lt; 0 || index &gt; size()).    */   public synchronized boolean addAll(int index, Collection c)   {     int len = array_.length;     if (index > len || index < 0)       throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + len);     int numNew = c.size();     if (numNew == 0)       return false;     Object[] newArray = new Object[len + numNew];     System.arraycopy(array_, 0, newArray, 0, len);     int numMoved = len - index;     if (numMoved > 0)       System.arraycopy(array_, index, newArray, index + numNew, numMoved);     Iterator e = c.iterator();     for (int i = 0; i < numNew; i++)       newArray[index++] = e.next();     array_ = newArray;     return true;   }   /**    * Check if the given index is in range. If not, throw an appropriate    * runtime exception.    * @param index     * @param length     */   protected void rangeCheck(int index, int length)   {     if (index >= length || index < 0)       throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + length);   }   /**    * Save the state of the list to a stream (i.e., serialize it).    * @param s     * @throws java.io.IOException     *     * @serialData The length of the array backing the list is emitted (int),    *             followed by all of its elements (each an Object) in the    *             proper order.    */   private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException   {     // Write out element count, and any hidden stuff     s.defaultWriteObject();     Object[] elementData = array();     // Write out array length     s.writeInt(elementData.length);     // Write out all elements in the proper order.     for (int i = 0; i < elementData.length; i++)       s.writeObject(elementData[i]);   }   /**    * Reconstitute the list from a stream (i.e., deserialize it).    * @param s     * @throws java.io.IOException     * @throws ClassNotFoundException     */   private synchronized void readObject(java.io.ObjectInputStream s) throws java.io.IOException,       ClassNotFoundException   {     // Read in size, and any hidden stuff     s.defaultReadObject();     // Read in array length and allocate array     int arrayLength = s.readInt();     Object[] elementData = new Object[arrayLength];     // Read in all elements in the proper order.     for (int i = 0; i < elementData.length; i++)       elementData[i] = s.readObject();     array_ = elementData;   }   /**    * Returns a string representation of this Collection, containing the String    * representation of each element.    */   public String toString()   {     StringBuffer buf = new StringBuffer();     Iterator e = iterator();     buf.append("[");     int maxIndex = size() - 1;     for (int i = 0; i <= maxIndex; i++)     {       buf.append(String.valueOf(e.next()));       if (i < maxIndex)         buf.append(", ");     }     buf.append("]");     return buf.toString();   }   /**    * Compares the specified Object with this List for equality. Returns true    * if and only if the specified Object is also a List, both Lists have the    * same size, and all corresponding pairs of elements in the two Lists are    * <em>equal</em>. (Two elements <code>e1</code> and <code>e2</code>    * are <em>equal</em> if    * <code>(e1==null ? e2==null : e1.equals(e2))</code>.) In other words,    * two Lists are defined to be equal if they contain the same elements in    * the same order.    * <p>    * This implementation first checks if the specified object is this List. If    * so, it returns true; if not, it checks if the specified object is a List.    * If not, it returns false; if so, it iterates over both lists, comparing    * corresponding pairs of elements. If any comparison returns false, this    * method returns false. If either Iterator runs out of elements before    * before the other it returns false (as the Lists are of unequal length);    * otherwise it returns true when the iterations complete.    *     * @param o    *            the Object to be compared for equality with this List.    * @return true if the specified Object is equal to this List.    */   public boolean equals(Object o)   {     if (o == this)       return true;     if (!(o instanceof List))       return false;     List l2 = (List)(o);     if (size() != l2.size())       return false;     ListIterator e1 = listIterator();     ListIterator e2 = l2.listIterator();     while (e1.hasNext())     {       Object o1 = e1.next();       Object o2 = e2.next();       if (!(o1 == null ? o2 == null : o1.equals(o2)))         return false;     }     return true;   }   /**    * Returns the hash code value for this List.    * <p>    * This implementation uses exactly the code that is used to define the List    * hash function in the documentation for List.hashCode.    */   public int hashCode()   {     int hashCode = 1;     Iterator i = iterator();     while (i.hasNext())     {       Object obj = i.next();       hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());     }     return hashCode;   }   /**    * Returns an Iterator over the elements contained in this collection. The    * iterator provides a snapshot of the state of the list when the iterator    * was constructed. No synchronization is needed while traversing the    * iterator. The iterator does <em>NOT</em> support the    * <code>remove</code> method.    */   public Iterator iterator()   {     return new COWIterator(array(), 0);   }   /**    * Returns an Iterator of the elements in this List (in proper sequence).    * The iterator provides a snapshot of the state of the list when the    * iterator was constructed. No synchronization is needed while traversing    * the iterator. The iterator does <em>NOT</em> support the    * <code>remove</code>, <code>set</code>, or <code>add</code>    * methods.    *     */   public ListIterator listIterator()   {     return new COWIterator(array(), 0);   }   /**    * Returns a ListIterator of the elements in this List (in proper sequence),    * starting at the specified position in the List. The specified index    * indicates the first element that would be returned by an initial call to    * nextElement. An initial call to previousElement would return the element    * with the specified index minus one. The ListIterator returned by this    * implementation will throw an UnsupportedOperationException in its remove,    * set and add methods.    *     * @param index    *            index of first element to be returned from the ListIterator    *            (by a call to getNext).    * @exception IndexOutOfBoundsException    *                index is out of range (index &lt; 0 || index &gt; size()).    */   public ListIterator listIterator(final int index)   {     Object[] elementData = array();     int len = elementData.length;     if (index < 0 || index > len)       throw new IndexOutOfBoundsException("Index: " + index);     return new COWIterator(array(), index);   }   protected static class COWIterator implements ListIterator   {     /** Snapshot of the array * */     protected final Object[] array;     /**      * Index of element to be returned by subsequent call to next.      */     protected int cursor;     protected COWIterator(Object[] elementArray, int initialCursor)     {       array = elementArray;       cursor = initialCursor;     }     public boolean hasNext()     {       return cursor < array.length;     }     public boolean hasPrevious()     {       return cursor > 0;     }     public Object next()     {       try       {         return array[cursor++];       }       catch (IndexOutOfBoundsException ex)       {         throw new NoSuchElementException();       }     }     public Object previous()     {       try       {         return array[--cursor];       }       catch (IndexOutOfBoundsException e)       {         throw new NoSuchElementException();       }     }     public int nextIndex()     {       return cursor;     }     public int previousIndex()     {       return cursor - 1;     }     /**      * Not supported. Always throws UnsupportedOperationException.      *       * @exception UnsupportedOperationException      *                remove is not supported by this Iterator.      */     public void remove()     {       throw new UnsupportedOperationException();     }     /**      * Not supported. Always throws UnsupportedOperationException.      *       * @exception UnsupportedOperationException      *                set is not supported by this Iterator.      */     public void set(Object o)     {       throw new UnsupportedOperationException();     }     /**      * Not supported. Always throws UnsupportedOperationException.      *       * @exception UnsupportedOperationException      *                add is not supported by this Iterator.      */     public void add(Object o)     {       throw new UnsupportedOperationException();     }   }   /**    * Returns a view of the portion of this List between fromIndex, inclusive,    * and toIndex, exclusive. The returned List is backed by this List, so    * changes in the returned List are reflected in this List, and vice-versa.    * While mutative operations are supported, they are probably not very    * useful for CopyOnWriteArrays.    * </p>    * The semantics of the List returned by this method become undefined if the    * backing list (i.e., this List) is <i>structurally modified</i> in any    * way other than via the returned List. (Structural modifications are those    * that change the size of the List, or otherwise perturb it in such a    * fashion that iterations in progress may yield incorrect results.)    *     * @param fromIndex    *            low endpoint (inclusive) of the subList.    * @param toKey    *            high endpoint (exclusive) of the subList.    * @return a view of the specified range within this List.    * @exception IndexOutOfBoundsException    *                Illegal endpoint index value (fromIndex &lt; 0 || toIndex    *                &gt; size || fromIndex &gt; toIndex).    */   public synchronized List subList(int fromIndex, int toIndex)   {     // synchronized since sublist ctor depends on it.     int len = array_.length;     if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)       throw new IndexOutOfBoundsException();     return new COWSubList(this, fromIndex, toIndex);   }   protected static class COWSubList extends AbstractList   {     /*      * This is currently a bit sleazy. The class extends AbstractList merely      * for convenience, to avoid having to define addAll, etc. This doesn't      * hurt, but is stupid and wasteful. This class does not need or use      * modCount mechanics in AbstractList, but does need to check for      * concurrent modification using similar mechanics. On each operation,      * the array that we expect the backing list to use is checked and      * updated. Since we do this for all of the base operations invoked by      * those defined in AbstractList, all is well.      *       * It's not clear whether this is worth cleaning up. The kinds of list      * operations inherited from AbstractList are are already so slow on COW      * sublists that adding a bit more space/time doesn't seem even      * noticeable.      */     protected final CopyOnWriteArrayList l;     protected final int offset;     protected int size;     protected Object[] expectedArray;     protected COWSubList(CopyOnWriteArrayList list, int fromIndex, int toIndex)     {       l = list;       expectedArray = l.array();       offset = fromIndex;       size = toIndex - fromIndex;     }     // only call this holding l's lock     protected void checkForComodification()     {       if (l.array_ != expectedArray)         throw new ConcurrentModificationException();     }     // only call this holding l's lock     protected void rangeCheck(int index)     {       if (index < 0 || index >= size)         throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size);     }     public Object set(int index, Object element)     {       synchronized (l)       {         rangeCheck(index);         checkForComodification();         Object x = l.set(index + offset, element);         expectedArray = l.array_;         return x;       }     }     public Object get(int index)     {       synchronized (l)       {         rangeCheck(index);         checkForComodification();         return l.get(index + offset);       }     }     public int size()     {       synchronized (l)       {         checkForComodification();         return size;       }     }     public void add(int index, Object element)     {       synchronized (l)       {         checkForComodification();         if (index < 0 || index > size)           throw new IndexOutOfBoundsException();         l.add(index + offset, element);         expectedArray = l.array_;         size++;       }     }     public Object remove(int index)     {       synchronized (l)       {         rangeCheck(index);         checkForComodification();         Object result = l.remove(index + offset);         expectedArray = l.array_;         size--;         return result;       }     }     public Iterator iterator()     {       synchronized (l)       {         checkForComodification();         return new COWSubListIterator(0);       }     }     public ListIterator listIterator(final int index)     {       synchronized (l)       {         checkForComodification();         if (index < 0 || index > size)           throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);         return new COWSubListIterator(index);       }     }     protected class COWSubListIterator implements ListIterator     {       protected final ListIterator i;       protected final int index;       protected COWSubListIterator(int index)       {         this.index = index;         i = l.listIterator(index + offset);       }       public boolean hasNext()       {         return nextIndex() < size;       }       public Object next()       {         if (hasNext())           return i.next();         else           throw new NoSuchElementException();       }       public boolean hasPrevious()       {         return previousIndex() >= 0;       }       public Object previous()       {         if (hasPrevious())           return i.previous();         else           throw new NoSuchElementException();       }       public int nextIndex()       {         return i.nextIndex() - offset;       }       public int previousIndex()       {         return i.previousIndex() - offset;       }       public void remove()       {         throw new UnsupportedOperationException();       }       public void set(Object o)       {         throw new UnsupportedOperationException();       }       public void add(Object o)       {         throw new UnsupportedOperationException();       }     }     public List subList(int fromIndex, int toIndex)     {       synchronized (l)       {         checkForComodification();         if (fromIndex < 0 || toIndex > size)           throw new IndexOutOfBoundsException();         return new COWSubList(l, fromIndex + offset, toIndex + offset);       }     }   } }