/* * @(#)AbstractList.java 1.48 05/08/27 * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util; /** * This class provides a skeletal implementation of the List * interface to minimize the effort required to implement this interface * backed by a "random access" data store (such as an array). For sequential * access data (such as a linked list), AbstractSequentialList should * be used in preference to this class.

* * To implement an unmodifiable list, the programmer needs only to extend this * class and provide implementations for the get(int index) and * size() methods.

* * To implement a modifiable list, the programmer must additionally override * the set(int index, Object element) method (which otherwise throws * an UnsupportedOperationException. If the list is variable-size * the programmer must additionally override the add(int index, Object * element) and remove(int index) methods.

* * The programmer should generally provide a void (no argument) and collection * constructor, as per the recommendation in the Collection interface * specification.

* * Unlike the other abstract collection implementations, the programmer does * not have to provide an iterator implementation; the iterator and * list iterator are implemented by this class, on top of the "random access" * methods: get(int index), set(int index, E element), * add(int index, E element) and remove(int index).

* * The documentation for each non-abstract methods in this class describes its * implementation in detail. Each of these methods may be overridden if the * collection being implemented admits a more efficient implementation.

* * This class is a member of the * * Java Collections Framework. * * @author Josh Bloch * @author Neal Gafter * @version 1.37, 01/18/03 * @see Collection * @see List * @see AbstractSequentialList * @see AbstractCollection * @since 1.2 */ public abstract class AbstractList extends AbstractCollection implements List { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractList() { } /** * Appends the specified element to the end of this list (optional * operation). * *

Lists that support this operation may place limitations on what * elements may be added to this list. In particular, some * lists will refuse to add null elements, and others will impose * restrictions on the type of elements that may be added. List * classes should clearly specify in their documentation any restrictions * on what elements may be added. * *

This implementation calls add(size(), e). * *

Note that this implementation throws an * UnsupportedOperationException unless add(int, Object) * is overridden. * * @param e element to be appended to this list * @return true (as specified by {@link Collection#add}) * @throws UnsupportedOperationException if the add operation * is not supported by this list * @throws ClassCastException if the class of the specified element * prevents it from being added to this list * @throws NullPointerException if the specified element is null and this * list does not permit null elements * @throws IllegalArgumentException if some property of this element * prevents it from being added to this list */ public boolean add(E e) { add(size(), e); return true; } /** * {@inheritDoc} * * @throws IndexOutOfBoundsException {@inheritDoc} */ abstract public E get(int index); /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { throw new UnsupportedOperationException(); } // Search Operations /** * {@inheritDoc} * *

This implementation first gets a list iterator (with * listIterator()). Then, it iterates over the list until the * specified element is found or the end of the list is reached. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public int indexOf(Object o) { ListIterator e = listIterator(); if (o==null) { while (e.hasNext()) if (e.next()==null) return e.previousIndex(); } else { while (e.hasNext()) if (o.equals(e.next())) return e.previousIndex(); } return -1; } /** * {@inheritDoc} * *

This implementation first gets a list iterator that points to the end * of the list (with listIterator(size())). Then, it iterates * backwards over the list until the specified element is found, or the * beginning of the list is reached. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public int lastIndexOf(Object o) { ListIterator e = listIterator(size()); if (o==null) { while (e.hasPrevious()) if (e.previous()==null) return e.nextIndex(); } else { while (e.hasPrevious()) if (o.equals(e.previous())) return e.nextIndex(); } return -1; } // Bulk Operations /** * Removes all of the elements from this list (optional operation). * The list will be empty after this call returns. * *

This implementation calls removeRange(0, size()). * *

Note that this implementation throws an * UnsupportedOperationException unless remove(int * index) or removeRange(int fromIndex, int toIndex) is * overridden. * * @throws UnsupportedOperationException if the clear operation * is not supported by this list */ public void clear() { removeRange(0, size()); } /** * {@inheritDoc} * *

This implementation gets an iterator over the specified collection and * iterates over it, inserting the elements obtained from the iterator * into this list at the appropriate position, one at a time, using * add(int, Object). Many implementations will override this * method for efficiency. * *

Note that this implementation throws an * UnsupportedOperationException unless add(int, Object) * is overridden. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public boolean addAll(int index, Collection c) { boolean modified = false; Iterator e = c.iterator(); while (e.hasNext()) { add(index++, e.next()); modified = true; } return modified; } // Iterators /** * Returns an iterator over the elements in this list in proper * sequence.

* * This implementation returns a straightforward implementation of the * iterator interface, relying on the backing list's size(), * get(int), and remove(int) methods.

* * Note that the iterator returned by this method will throw an * UnsupportedOperationException in response to its * remove method unless the list's remove(int) method is * overridden.

* * This implementation can be made to throw runtime exceptions in the face * of concurrent modification, as described in the specification for the * (protected) modCount field. * * @return an iterator over the elements in this list in proper sequence * * @see #modCount */ public Iterator iterator() { return new Itr(); } /** * {@inheritDoc} * *

This implementation returns listIterator(0). * * @see #listIterator(int) */ public ListIterator listIterator() { return listIterator(0); } /** * {@inheritDoc} * *

This implementation returns a straightforward implementation of the * ListIterator interface that extends the implementation of the * Iterator interface returned by the iterator() method. * The ListIterator implementation relies on the backing list's * get(int), set(int, Object), add(int, Object) * and remove(int) methods. * *

Note that the list iterator returned by this implementation will * throw an UnsupportedOperationException in response to its * remove, set and add methods unless the * list's remove(int), set(int, Object), and * add(int, Object) methods are overridden. * *

This implementation can be made to throw runtime exceptions in the * face of concurrent modification, as described in the specification for * the (protected) modCount field. * * @throws IndexOutOfBoundsException {@inheritDoc} * * @see #modCount */ public ListIterator listIterator(final int index) { if (index<0 || index>size()) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } private class Itr implements Iterator { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; /** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */ int lastRet = -1; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount; public final boolean hasNext() { return cursor < size(); } public final E next() { try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException ex) { throw new NoSuchElementException(); } finally { if (expectedModCount != modCount) throw new ConcurrentModificationException(); } } public final void remove() { if (lastRet == -1) throw new IllegalStateException(); if (expectedModCount != modCount) throw new ConcurrentModificationException(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } } private final class ListItr extends Itr implements ListIterator { ListItr(int index) { cursor = index; } public boolean hasPrevious() { return cursor > 0; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public E previous() { try { int i = cursor - 1; E prev = get(i); lastRet = i; cursor = i; return prev; } catch (IndexOutOfBoundsException ex) { throw new NoSuchElementException(); } finally { if (expectedModCount != modCount) throw new ConcurrentModificationException(); } } public void set(E e) { if (lastRet == -1) throw new IllegalStateException(); if (expectedModCount != modCount) throw new ConcurrentModificationException(); try { AbstractList.this.set(lastRet, e); expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { if (expectedModCount != modCount) throw new ConcurrentModificationException(); try { int i = cursor; AbstractList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } } /** * {@inheritDoc} * *

This implementation returns a list that subclasses * AbstractList. The subclass stores, in private fields, the * offset of the subList within the backing list, the size of the subList * (which can change over its lifetime), and the expected * modCount value of the backing list. There are two variants * of the subclass, one of which implements RandomAccess. * If this list implements RandomAccess the returned list will * be an instance of the subclass that implements RandomAccess. * *

The subclass's set(int, Object), get(int), * add(int, Object), remove(int), addAll(int, * Collection) and removeRange(int, int) methods all * delegate to the corresponding methods on the backing abstract list, * after bounds-checking the index and adjusting for the offset. The * addAll(Collection c) method merely returns addAll(size, * c). * *

The listIterator(int) method returns a "wrapper object" * over a list iterator on the backing list, which is created with the * corresponding method on the backing list. The iterator method * merely returns listIterator(), and the size method * merely returns the subclass's size field. * *

All methods first check to see if the actual modCount of * the backing list is equal to its expected value, and throw a * ConcurrentModificationException if it is not. * * @throws IndexOutOfBoundsException endpoint index value out of range * (fromIndex < 0 || toIndex > size) * @throws IllegalArgumentException if the endpoint indices are out of order * (fromIndex > toIndex) */ public List subList(int fromIndex, int toIndex) { return (this instanceof RandomAccess ? new RandomAccessSubList(this, fromIndex, toIndex) : new SubList(this, fromIndex, toIndex)); } // Comparison and hashing /** * 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 equal. (Two elements e1 and * e2 are equal if (e1==null ? e2==null : * e1.equals(e2)).) In other words, two lists are defined to be * equal if they contain the same elements in the same order.

* * 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 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; ListIterator e1 = listIterator(); ListIterator e2 = ((List) o).listIterator(); while(e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return !(e1.hasNext() || e2.hasNext()); } /** * Returns the hash code value for this list.

* * This implementation uses exactly the code that is used to define the * list hash function in the documentation for the {@link List#hashCode} * method. * * @return the hash code value for this list */ public int hashCode() { int hashCode = 1; Iterator i = iterator(); while (i.hasNext()) { E obj = i.next(); hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode()); } return hashCode; } /** * 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 ArrayList by (toIndex - fromIndex) * elements. (If toIndex==fromIndex, this operation has no * effect.)

* * This method is called by the clear operation on this list * and its subLists. Overriding this method to take advantage of * the internals of the list implementation can substantially * improve the performance of the clear operation on this list * and its subLists.

* * This implementation gets a list iterator positioned before * fromIndex, and repeatedly calls ListIterator.next * followed by ListIterator.remove until the entire range has * been removed. Note: if ListIterator.remove requires linear * time, this implementation requires quadratic time. * * @param fromIndex index of first element to be removed * @param toIndex index after last element to be removed */ protected void removeRange(int fromIndex, int toIndex) { ListIterator it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; istructurally modified. * 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.

* * This field is used by the iterator and list iterator implementation * returned by the iterator and listIterator methods. * If the value of this field changes unexpectedly, the iterator (or list * iterator) will throw a ConcurrentModificationException in * response to the next, remove, previous, * set or add operations. This provides * fail-fast behavior, rather than non-deterministic behavior in * the face of concurrent modification during iteration.

* * Use of this field by subclasses is optional. If a subclass * wishes to provide fail-fast iterators (and list iterators), then it * merely has to increment this field in its add(int, Object) and * remove(int) methods (and any other methods that it overrides * that result in structural modifications to the list). A single call to * add(int, Object) or remove(int) must add no more than * one to this field, or the iterators (and list iterators) will throw * bogus ConcurrentModificationExceptions. If an implementation * does not wish to provide fail-fast iterators, this field may be * ignored. */ protected transient int modCount = 0; } class SubList extends AbstractList { private AbstractList l; private int offset; private int size; private int expectedModCount; SubList(AbstractList list, int fromIndex, int toIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > list.size()) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); l = list; offset = fromIndex; size = toIndex - fromIndex; expectedModCount = l.modCount; } public E set(int index, E element) { rangeCheck(index); checkForComodification(); return l.set(index+offset, element); } public E get(int index) { rangeCheck(index); checkForComodification(); return l.get(index+offset); } public int size() { checkForComodification(); return size; } public void add(int index, E element) { if (index<0 || index>size) throw new IndexOutOfBoundsException(); checkForComodification(); l.add(index+offset, element); expectedModCount = l.modCount; size++; modCount++; } public E remove(int index) { rangeCheck(index); checkForComodification(); E result = l.remove(index+offset); expectedModCount = l.modCount; size--; modCount++; return result; } protected void removeRange(int fromIndex, int toIndex) { checkForComodification(); l.removeRange(fromIndex+offset, toIndex+offset); expectedModCount = l.modCount; size -= (toIndex-fromIndex); modCount++; } public boolean addAll(Collection c) { return addAll(size, c); } public boolean addAll(int index, Collection c) { if (index<0 || index>size) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); int cSize = c.size(); if (cSize==0) return false; checkForComodification(); l.addAll(offset+index, c); expectedModCount = l.modCount; size += cSize; modCount++; return true; } public Iterator iterator() { return listIterator(); } public ListIterator listIterator(final int index) { checkForComodification(); if (index<0 || index>size) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); return new ListIterator() { private ListIterator i = l.listIterator(index+offset); public boolean hasNext() { return nextIndex() < size; } public E next() { if (hasNext()) return i.next(); else throw new NoSuchElementException(); } public boolean hasPrevious() { return previousIndex() >= 0; } public E 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() { i.remove(); expectedModCount = l.modCount; size--; modCount++; } public void set(E e) { i.set(e); } public void add(E e) { i.add(e); expectedModCount = l.modCount; size++; modCount++; } }; } public List subList(int fromIndex, int toIndex) { return new SubList(this, fromIndex, toIndex); } private void rangeCheck(int index) { if (index<0 || index>=size) throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+size); } private void checkForComodification() { if (l.modCount != expectedModCount) throw new ConcurrentModificationException(); } } class RandomAccessSubList extends SubList implements RandomAccess { RandomAccessSubList(AbstractList list, int fromIndex, int toIndex) { super(list, fromIndex, toIndex); } public List subList(int fromIndex, int toIndex) { return new RandomAccessSubList(this, fromIndex, toIndex); } }