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 : ArrayList « Collections Data Structure « Java






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

     
/*
 * 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);
      }
    }


  }

}

   
    
    
    
    
  








Related examples in the same category

1.Get the size of an arraylist after and before add and remove methods
2.Use the Iterator returned from ArrayList to loop through an array list
3.Get generic Iterator from generic ArrayList
4.Convert an ArrayList into an array.
5.Pre-generics example that uses a collection.
6.shows the modern, generic form of collection classes
7.Use set method to change the value in an array list
8.Store user-defined objects in arraylist
9.pass the actual object you want removed.
10.Convert a List (ArrayList) to an Array with zero length array
11.Convert a List (ArrayList) to an Array with full length array
12.Remove duplicate items from an ArrayList
13.Looping through a Collection object: while loop, iterator, and for each
14.Append all elements of other Collection to Java ArrayList
15.Copy all elements of Java ArrayList to an Object Array
16.Get Size of Java ArrayList and loop through elements
17.Add an element to specified index of Java ArrayList
18.Get Sub List of Java ArrayList
19.Insert all elements of other Collection to Specified Index of Java ArrayList
20.Iterate through elements Java ArrayList using Iterator
21.Iterate through elements Java ArrayList using ListIterator
22.Remove all elements from Java ArrayList
23.Remove an element from specified index of Java ArrayList
24.Search an element of Java ArrayList
25.Get element in an ArrayList by index
26.Replace an element at specified index of Java ArrayList
27.Sort elements of Java ArrayList
28.Copy Elements of ArrayList to Java Vector
29.Copy Elements of One Java ArrayList to Another Java ArrayList
30.Find maximum element of Java ArrayList
31.Find Minimum element of Java ArrayList
32.Get Enumeration over Java ArrayList
33.Get Synchronized List from Java ArrayList
34.Perform Binary Search on Java ArrayList
35.Replace All Elements Of Java ArrayList
36.Replace all occurrences of specified element of Java ArrayList
37.Reverse order of all elements of Java ArrayList
38.Shuffle elements of Java ArrayList
39.Swap elements of Java ArrayList
40.Iterate through a Collection using Java Iterator
41.Sort Java ArrayList in descending order using comparator
42.Remove an element from Collection using Java Iterator
43.Replace an element from ArrayList using Java ListIterator
44.How to Convert an ArrayList into an array
45.Sort items of an ArrayList
46.Rotate elements of a collection
47.Search collection element
48.If an ArrayList contains a given item
49.Convert Collection to ArrayList?
50.A boolean is being stored and then retrieved from an ArrayList
51.Traverse through ArrayList in reverse direction using Java ListIterator
52.Traverse through ArrayList in forward direction using Java ListIterator
53.Remove an element from ArrayList using Java ListIterator
54.Get Previous and next index using Java ListIterator
55.A Map implemented with ArrayLists
56.Copy On Write ArrayList
57.This program demonstrates the ArrayList class
58.ArrayList with sorted contents.