All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.util.AbstractList Maven / Gradle / Ivy

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package java.util;

/**
 * {@code AbstractList} is an abstract implementation of the {@code List} interface, optimized
 * for a backing store which supports random access. This implementation does
 * not support adding or replacing. A subclass must implement the abstract
 * methods {@code get()} and {@code size()}, and to create a
 * modifiable {@code List} it's necessary to override the {@code add()} method that
 * currently throws an {@code UnsupportedOperationException}.
 *
 * @since 1.2
 */
public abstract class AbstractList extends AbstractCollection implements List {

    /**
     * A counter for changes to the list.
     */
    protected transient int modCount;

    private class SimpleListIterator implements Iterator {
        int pos = -1;

        int expectedModCount;

        int lastPosition = -1;

        SimpleListIterator() {
            expectedModCount = modCount;
        }

        public boolean hasNext() {
            return pos + 1 < size();
        }

        public E next() {
            if (expectedModCount == modCount) {
                try {
                    E result = get(pos + 1);
                    lastPosition = ++pos;
                    return result;
                } catch (IndexOutOfBoundsException e) {
                    throw new NoSuchElementException();
                }
            }
            throw new ConcurrentModificationException();
        }

        public void remove() {
            if (this.lastPosition == -1) {
                throw new IllegalStateException();
            }

            if (expectedModCount != modCount) {
                throw new ConcurrentModificationException();
            }

            try {
                AbstractList.this.remove(lastPosition);
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }

            expectedModCount = modCount;
            if (pos == lastPosition) {
                pos--;
            }
            lastPosition = -1;
        }
    }

    private final class FullListIterator extends SimpleListIterator implements ListIterator {
        FullListIterator(int start) {
            if (start >= 0 && start <= size()) {
                pos = start - 1;
            } else {
                throw new IndexOutOfBoundsException();
            }
        }

        public void add(E object) {
            if (expectedModCount == modCount) {
                try {
                    AbstractList.this.add(pos + 1, object);
                } catch (IndexOutOfBoundsException e) {
                    throw new NoSuchElementException();
                }
                pos++;
                lastPosition = -1;
                if (modCount != expectedModCount) {
                    expectedModCount = modCount;
                }
            } else {
                throw new ConcurrentModificationException();
            }
        }

        public boolean hasPrevious() {
            return pos >= 0;
        }

        public int nextIndex() {
            return pos + 1;
        }

        public E previous() {
            if (expectedModCount == modCount) {
                try {
                    E result = get(pos);
                    lastPosition = pos;
                    pos--;
                    return result;
                } catch (IndexOutOfBoundsException e) {
                    throw new NoSuchElementException();
                }
            }
            throw new ConcurrentModificationException();
        }

        public int previousIndex() {
            return pos;
        }

        public void set(E object) {
            if (expectedModCount == modCount) {
                try {
                    AbstractList.this.set(lastPosition, object);
                } catch (IndexOutOfBoundsException e) {
                    throw new IllegalStateException();
                }
            } else {
                throw new ConcurrentModificationException();
            }
        }
    }

    private static final class SubAbstractListRandomAccess extends
            SubAbstractList implements RandomAccess {
        SubAbstractListRandomAccess(AbstractList list, int start, int end) {
            super(list, start, end);
        }
    }

    private static class SubAbstractList extends AbstractList {
        private final AbstractList fullList;

        private int offset;

        private int size;

        private static final class SubAbstractListIterator implements
                ListIterator {
            private final SubAbstractList subList;

            private final ListIterator iterator;

            private int start;

            private int end;

            SubAbstractListIterator(ListIterator it,
									SubAbstractList list, int offset, int length) {
                iterator = it;
                subList = list;
                start = offset;
                end = start + length;
            }

            public void add(E object) {
                iterator.add(object);
                subList.sizeChanged(true);
                end++;
            }

            public boolean hasNext() {
                return iterator.nextIndex() < end;
            }

            public boolean hasPrevious() {
                return iterator.previousIndex() >= start;
            }

            public E next() {
                if (iterator.nextIndex() < end) {
                    return iterator.next();
                }
                throw new NoSuchElementException();
            }

            public int nextIndex() {
                return iterator.nextIndex() - start;
            }

            public E previous() {
                if (iterator.previousIndex() >= start) {
                    return iterator.previous();
                }
                throw new NoSuchElementException();
            }

            public int previousIndex() {
                int previous = iterator.previousIndex();
                if (previous >= start) {
                    return previous - start;
                }
                return -1;
            }

            public void remove() {
                iterator.remove();
                subList.sizeChanged(false);
                end--;
            }

            public void set(E object) {
                iterator.set(object);
            }
        }

        SubAbstractList(AbstractList list, int start, int end) {
            fullList = list;
            modCount = fullList.modCount;
            offset = start;
            size = end - start;
        }

        @Override
        public void add(int location, E object) {
            if (modCount == fullList.modCount) {
                if (location >= 0 && location <= size) {
                    fullList.add(location + offset, object);
                    size++;
                    modCount = fullList.modCount;
                } else {
                    throw new IndexOutOfBoundsException();
                }
            } else {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        public boolean addAll(int location, Collection collection) {
            if (modCount == fullList.modCount) {
                if (location >= 0 && location <= size) {
                    boolean result = fullList.addAll(location + offset,
                            collection);
                    if (result) {
                        size += collection.size();
                        modCount = fullList.modCount;
                    }
                    return result;
                }
                throw new IndexOutOfBoundsException();
            }
            throw new ConcurrentModificationException();
        }

        @Override
        public boolean addAll(Collection collection) {
            if (modCount == fullList.modCount) {
                boolean result = fullList.addAll(offset + size, collection);
                if (result) {
                    size += collection.size();
                    modCount = fullList.modCount;
                }
                return result;
            }
            throw new ConcurrentModificationException();
        }

        @Override
        public E get(int location) {
            if (modCount == fullList.modCount) {
                if (location >= 0 && location < size) {
                    return fullList.get(location + offset);
                }
                throw new IndexOutOfBoundsException();
            }
            throw new ConcurrentModificationException();
        }

        @Override
        public Iterator iterator() {
            return listIterator(0);
        }

        @Override
        public ListIterator listIterator(int location) {
            if (modCount == fullList.modCount) {
                if (location >= 0 && location <= size) {
                    return new SubAbstractListIterator(fullList
                            .listIterator(location + offset), this, offset,
                            size);
                }
                throw new IndexOutOfBoundsException();
            }
            throw new ConcurrentModificationException();
        }

        @Override
        public E remove(int location) {
            if (modCount == fullList.modCount) {
                if (location >= 0 && location < size) {
                    E result = fullList.remove(location + offset);
                    size--;
                    modCount = fullList.modCount;
                    return result;
                }
                throw new IndexOutOfBoundsException();
            }
            throw new ConcurrentModificationException();
        }

        @Override
        protected void removeRange(int start, int end) {
            if (start != end) {
                if (modCount == fullList.modCount) {
                    fullList.removeRange(start + offset, end + offset);
                    size -= end - start;
                    modCount = fullList.modCount;
                } else {
                    throw new ConcurrentModificationException();
                }
            }
        }

        @Override
        public E set(int location, E object) {
            if (modCount == fullList.modCount) {
                if (location >= 0 && location < size) {
                    return fullList.set(location + offset, object);
                }
                throw new IndexOutOfBoundsException();
            }
            throw new ConcurrentModificationException();
        }

        @Override
        public int size() {
            if (modCount == fullList.modCount) {
                return size;
            }
            throw new ConcurrentModificationException();
        }

        void sizeChanged(boolean increment) {
            if (increment) {
                size++;
            } else {
                size--;
            }
            modCount = fullList.modCount;
        }
    }

    /**
     * Constructs a new instance of this AbstractList.
     */
    protected AbstractList() {
    }

    /**
     * Inserts the specified object into this List at the specified location.
     * The object is inserted before any previous element at the specified
     * location. If the location is equal to the size of this List, the object
     * is added at the end.
     * 

* Concrete implementations that would like to support the add functionality * must override this method. * * @param location * the index at which to insert. * @param object * the object to add. * * @throws UnsupportedOperationException * if adding to this List is not supported. * @throws ClassCastException * if the class of the object is inappropriate for this * List * @throws IllegalArgumentException * if the object cannot be added to this List * @throws IndexOutOfBoundsException * if {@code location < 0 || location > size()} */ public void add(int location, E object) { throw new UnsupportedOperationException(); } /** * Adds the specified object at the end of this List. * * * @param object * the object to add * @return true * * @throws UnsupportedOperationException * if adding to this List is not supported * @throws ClassCastException * if the class of the object is inappropriate for this * List * @throws IllegalArgumentException * if the object cannot be added to this List */ @Override public boolean add(E object) { add(size(), object); return true; } /** * Inserts the objects in the specified Collection at the specified location * in this List. The objects are added in the order they are returned from * the collection's iterator. * * @param location * the index at which to insert. * @param collection * the Collection of objects * @return {@code true} if this List is modified, {@code false} otherwise. * @throws UnsupportedOperationException * if adding to this list is not supported. * @throws ClassCastException * if the class of an object is inappropriate for this list. * @throws IllegalArgumentException * if an object cannot be added to this list. * @throws IndexOutOfBoundsException * if {@code location < 0 || location > size()} */ public boolean addAll(int location, Collection collection) { Iterator it = collection.iterator(); while (it.hasNext()) { add(location++, it.next()); } return !collection.isEmpty(); } /** * Removes all elements from this list, leaving it empty. * * @throws UnsupportedOperationException * if removing from this list is not supported. * @see List#isEmpty * @see List#size */ @Override public void clear() { removeRange(0, size()); } /** * Compares the specified object to this list and return true if they are * equal. Two lists are equal when they both contain the same objects in the * same order. * * @param object * the object to compare to this object. * @return {@code true} if the specified object is equal to this list, * {@code false} otherwise. * @see #hashCode */ @Override public boolean equals(Object object) { if (this == object) { return true; } if (object instanceof List) { List list = (List) object; if (list.size() != size()) { return false; } Iterator it1 = iterator(), it2 = list.iterator(); while (it1.hasNext()) { Object e1 = it1.next(), e2 = it2.next(); if (!(e1 == null ? e2 == null : e1.equals(e2))) { return false; } } return true; } return false; } /** * Returns the element at the specified location in this list. * * @param location * the index of the element to return. * @return the element at the specified index. * @throws IndexOutOfBoundsException * if {@code location < 0 || location >= size()} */ public abstract E get(int location); /** * Returns the hash code of this list. The hash code is calculated by taking * each element's hashcode into account. * * @return the hash code. * @see #equals * @see List#hashCode() */ @Override public int hashCode() { int result = 1; Iterator it = iterator(); while (it.hasNext()) { Object object = it.next(); result = (31 * result) + (object == null ? 0 : object.hashCode()); } return result; } /** * Searches this list for the specified object and returns the index of the * first occurrence. * * @param object * the object to search for. * @return the index of the first occurrence of the object, or -1 if it was * not found. */ public int indexOf(Object object) { ListIterator it = listIterator(); if (object != null) { while (it.hasNext()) { if (object.equals(it.next())) { return it.previousIndex(); } } } else { while (it.hasNext()) { if (it.next() == null) { return it.previousIndex(); } } } return -1; } /** * Returns an iterator on the elements of this list. The elements are * iterated in the same order as they occur in the list. * * @return an iterator on the elements of this list. * @see Iterator */ @Override public Iterator iterator() { return new SimpleListIterator(); } /** * Searches this list for the specified object and returns the index of the * last occurrence. * * @param object * the object to search for. * @return the index of the last occurrence of the object, or -1 if the * object was not found. */ public int lastIndexOf(Object object) { ListIterator it = listIterator(size()); if (object != null) { while (it.hasPrevious()) { if (object.equals(it.previous())) { return it.nextIndex(); } } } else { while (it.hasPrevious()) { if (it.previous() == null) { return it.nextIndex(); } } } return -1; } /** * Returns a ListIterator on the elements of this list. The elements are * iterated in the same order that they occur in the list. * * @return a ListIterator on the elements of this list * @see ListIterator */ public ListIterator listIterator() { return listIterator(0); } /** * Returns a list iterator on the elements of this list. The elements are * iterated in the same order as they occur in the list. The iteration * starts at the specified location. * * @param location * the index at which to start the iteration. * @return a ListIterator on the elements of this list. * @throws IndexOutOfBoundsException * if {@code location < 0 || location > size()} * @see ListIterator */ public ListIterator listIterator(int location) { return new FullListIterator(location); } /** * Removes the object at the specified location from this list. * * @param location * the index of the object to remove. * @return the removed object. * @throws UnsupportedOperationException * if removing from this list is not supported. * @throws IndexOutOfBoundsException * if {@code location < 0 || location >= size()} */ public E remove(int location) { throw new UnsupportedOperationException(); } /** * Removes the objects in the specified range from the start to the end * index minus one. * * @param start * the index at which to start removing. * @param end * the index after the last element to remove. * @throws UnsupportedOperationException * if removing from this list is not supported. * @throws IndexOutOfBoundsException * if {@code start < 0} or {@code start >= size()}. */ protected void removeRange(int start, int end) { Iterator it = listIterator(start); for (int i = start; i < end; i++) { it.next(); it.remove(); } } /** * Replaces the element at the specified location in this list with the * specified object. * * @param location * the index at which to put the specified object. * @param object * the object to add. * @return the previous element at the index. * @throws UnsupportedOperationException * if replacing elements in this list is not supported. * @throws ClassCastException * if the class of an object is inappropriate for this list. * @throws IllegalArgumentException * if an object cannot be added to this list. * @throws IndexOutOfBoundsException * if {@code location < 0 || location >= size()} */ public E set(int location, E object) { throw new UnsupportedOperationException(); } /** * Returns a part of consecutive elements of this list as a view. The * returned view will be of zero length if start equals end. Any change that * occurs in the returned subList will be reflected to the original list, * and vice-versa. All the supported optional operations by the original * list will also be supported by this subList. *

* This method can be used as a handy method to do some operations on a sub * range of the original list, for example * {@code list.subList(from, to).clear();} *

* If the original list is modified in other ways than through the returned * subList, the behavior of the returned subList becomes undefined. *

* The returned subList is a subclass of AbstractList. The subclass stores * offset, size of itself, and modCount of the original list. If the * original list implements RandomAccess interface, the returned subList * also implements RandomAccess interface. *

* The subList's set(int, Object), get(int), add(int, Object), remove(int), * addAll(int, Collection) and removeRange(int, int) methods first check the * bounds, adjust offsets and then call the corresponding methods of the * original AbstractList. addAll(Collection c) method of the returned * subList calls the original addAll(offset + size, c). *

* The listIterator(int) method of the subList wraps the original list * iterator. The iterator() method of the subList invokes the original * listIterator() method, and the size() method merely returns the size of * the subList. *

* All methods will throw a ConcurrentModificationException if the modCount * of the original list is not equal to the expected value. * * @param start * start index of the subList (inclusive). * @param end * end index of the subList, (exclusive). * @return a subList view of this list starting from {@code start} * (inclusive), and ending with {@code end} (exclusive) * @throws IndexOutOfBoundsException * if (start < 0 || end > size()) * @throws IllegalArgumentException * if (start > end) */ public List subList(int start, int end) { if (start >= 0 && end <= size()) { if (start <= end) { if (this instanceof RandomAccess) { return new SubAbstractListRandomAccess(this, start, end); } return new SubAbstractList(this, start, end); } throw new IllegalArgumentException(); } throw new IndexOutOfBoundsException(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy