org.apache.commons.collections15.list.SetUniqueList.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.commons.collections15.list.SetUniqueList.java

Source

// GenericsNote: Converted.
/*
 *  Copyright 2001-2004 The Apache Software Foundation
 *
 *  Licensed 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 org.apache.commons.collections15.list;

import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
import org.apache.commons.collections15.iterators.AbstractListIteratorDecorator;
import org.apache.commons.collections15.set.UnmodifiableSet;

import java.util.*;

/**
 * Decorates a <code>List</code> to ensure that no duplicates are present
 * much like a <code>Set</code>.
 * <p/>
 * The <code>List</code> interface makes certain assumptions/requirements.
 * This implementation breaks these in certain ways, but this is merely the
 * result of rejecting duplicates.
 * Each violation is explained in the method, but it should not affect you.
 * <p/>
 * The {@link org.apache.commons.collections15.set.ListOrderedSet ListOrderedSet}
 * class provides an alternative approach, by wrapping an existing Set and
 * retaining insertion order in the iterator.
 * <p/>
 * This class is Serializable from Commons Collections 3.1.
 *
 * @author Matthew Hawthorne
 * @author Matt Hall, John Watkinson, Stephen Colebourne
 * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
 * @since Commons Collections 3.0
 */
public class SetUniqueList<E> extends AbstractSerializableListDecorator<E> {

    /**
     * Serialization version
     */
    private static final long serialVersionUID = 7196982186153478694L;

    /**
     * Internal Set to maintain uniqueness.
     */
    protected final Set<E> set;

    /**
     * Factory method to create a SetList using the supplied list to retain order.
     * <p/>
     * If the list contains duplicates, these are removed (first indexed one kept).
     * A <code>HashSet</code> is used for the set behaviour.
     *
     * @param list the list to decorate, must not be null
     * @throws IllegalArgumentException if list is null
     */
    public static <E> SetUniqueList<E> decorate(List<E> list) {
        if (list == null) {
            throw new IllegalArgumentException("List must not be null");
        }
        if (list.isEmpty()) {
            return new SetUniqueList<E>(list, new HashSet());
        } else {
            List temp = new ArrayList(list);
            list.clear();
            SetUniqueList<E> sl = new SetUniqueList<E>(list, new HashSet());
            sl.addAll(temp);
            return sl;
        }
    }

    //-----------------------------------------------------------------------
    /**
     * Constructor that wraps (not copies) the List and specifies the set to use.
     * <p/>
     * The set and list must both be correctly initialised to the same elements.
     *
     * @param set  the set to decorate, must not be null
     * @param list the list to decorate, must not be null
     * @throws IllegalArgumentException if set or list is null
     */
    protected SetUniqueList(List<E> list, Set<E> set) {
        super(list);
        if (set == null) {
            throw new IllegalArgumentException("Set must not be null");
        }
        this.set = set;
    }

    //-----------------------------------------------------------------------
    /**
     * Gets an unmodifiable view as a Set.
     *
     * @return an unmodifiable set view
     */
    public Set<E> asSet() {
        return UnmodifiableSet.decorate(set);
    }

    //-----------------------------------------------------------------------
    /**
     * Adds an element to the list if it is not already present.
     * <p/>
     * <i>(Violation)</i>
     * The <code>List</code> interface requires that this method returns
     * <code>true</code> always. However this class may return <code>false</code>
     * because of the <code>Set</code> behaviour.
     *
     * @param object the object to add
     * @return true if object was added
     */
    public boolean add(E object) {
        // gets initial size
        final int sizeBefore = size();

        // adds element if unique
        add(size(), object);

        // compares sizes to detect if collection changed
        return (sizeBefore != size());
    }

    /**
     * Adds an element to a specific index in the list if it is not already present.
     * <p/>
     * <i>(Violation)</i>
     * The <code>List</code> interface makes the assumption that the element is
     * always inserted. This may not happen with this implementation.
     *
     * @param index  the index to insert at
     * @param object the object to add
     */
    public void add(int index, E object) {
        // adds element if it is not contained already
        if (set.contains(object) == false) {
            super.add(index, object);
            set.add(object);
        }
    }

    /**
     * Adds an element to the end of the list if it is not already present.
     * <p/>
     * <i>(Violation)</i>
     * The <code>List</code> interface makes the assumption that the element is
     * always inserted. This may not happen with this implementation.
     *
     * @param coll the collection to add
     */
    public boolean addAll(Collection<? extends E> coll) {
        return addAll(size(), coll);
    }

    /**
     * Adds a collection of objects to the end of the list avoiding duplicates.
     * <p/>
     * Only elements that are not already in this list will be added, and
     * duplicates from the specified collection will be ignored.
     * <p/>
     * <i>(Violation)</i>
     * The <code>List</code> interface makes the assumption that the elements
     * are always inserted. This may not happen with this implementation.
     *
     * @param index the index to insert at
     * @param coll  the collection to add in iterator order
     * @return true if this collection changed
     */
    public boolean addAll(int index, Collection<? extends E> coll) {
        // gets initial size
        final int sizeBefore = size();

        // adds all elements
        for (final Iterator it = coll.iterator(); it.hasNext();) {
            add((E) it.next());
        }

        // compares sizes to detect if collection changed
        return sizeBefore != size();
    }

    //-----------------------------------------------------------------------
    /**
     * Sets the value at the specified index avoiding duplicates.
     * <p/>
     * The object is set into the specified index.
     * Afterwards, any previous duplicate is removed
     * If the object is not already in the list then a normal set occurs.
     * If it is present, then the old version is removed and re-added at this index
     *
     * @param index  the index to insert at
     * @param object the object to set
     * @return the previous object
     */
    public E set(int index, E object) {
        int pos = indexOf(object);
        E result = super.set(index, object);
        if (pos == -1 || pos == index) {
            return result;
        }
        return remove(pos);
    }

    public boolean remove(Object object) {
        boolean result = super.remove(object);
        set.remove(object);
        return result;
    }

    public E remove(int index) {
        E result = super.remove(index);
        set.remove(result);
        return result;
    }

    public boolean removeAll(Collection<?> coll) {
        boolean result = super.removeAll(coll);
        set.removeAll(coll);
        return result;
    }

    public boolean retainAll(Collection<?> coll) {
        boolean result = super.retainAll(coll);
        set.retainAll(coll);
        return result;
    }

    public void clear() {
        super.clear();
        set.clear();
    }

    public boolean contains(Object object) {
        return set.contains(object);
    }

    public boolean containsAll(Collection<?> coll) {
        return set.containsAll(coll);
    }

    public Iterator<E> iterator() {
        return new SetListIterator(super.iterator(), set);
    }

    public ListIterator<E> listIterator() {
        return new SetListListIterator(super.listIterator(), set);
    }

    public ListIterator<E> listIterator(int index) {
        return new SetListListIterator(super.listIterator(index), set);
    }

    public List<E> subList(int fromIndex, int toIndex) {
        return new SetUniqueList<E>(super.subList(fromIndex, toIndex), set);
    }

    //-----------------------------------------------------------------------
    /**
     * Inner class iterator.
     */
    static class SetListIterator<E> extends AbstractIteratorDecorator<E> {

        protected final Set<E> set;
        protected E last = null;

        protected SetListIterator(Iterator<E> it, Set<E> set) {
            super(it);
            this.set = set;
        }

        public E next() {
            last = super.next();
            return last;
        }

        public void remove() {
            super.remove();
            set.remove(last);
            last = null;
        }
    }

    /**
     * Inner class iterator.
     */
    static class SetListListIterator<E> extends AbstractListIteratorDecorator<E> {

        protected final Set<E> set;
        protected E last = null;

        protected SetListListIterator(ListIterator<E> it, Set<E> set) {
            super(it);
            this.set = set;
        }

        public E next() {
            last = super.next();
            return last;
        }

        public E previous() {
            last = super.previous();
            return last;
        }

        public void remove() {
            super.remove();
            set.remove(last);
            last = null;
        }

        public void add(E object) {
            if (set.contains(object) == false) {
                super.add(object);
                set.add(object);
            }
        }

        public void set(E object) {
            throw new UnsupportedOperationException("ListIterator does not support set");
        }
    }

}