AbstractCollection.java revision 2ad60cfc28e14ee8f0bb038720836a4696c478ad
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.util;
19
20
21import java.lang.reflect.Array;
22
23/**
24 * AbstractCollection is an abstract implementation of the Collection interface.
25 * This implementation does not support adding. A subclass must implement the
26 * abstract methods iterator() and size().
27 * @since 1.2
28 */
29public abstract class AbstractCollection<E> implements Collection<E> {
30
31    /**
32     * Constructs a new instance of this AbstractCollection.
33     */
34    protected AbstractCollection() {
35        super();
36    }
37
38    /**
39     * If the specified element is not contained within this collection, and
40     * addition of this element succeeds, then true will be returned. If the
41     * specified element is already contained within this collection, or
42     * duplication is not permitted, false will be returned. Different
43     * implementations may add specific limitations on this method to filter
44     * permitted elements. For example, in some implementation, null element may
45     * be denied, and NullPointerException will be thrown out. These limitations
46     * should be explicitly documented by specific collection implementation.
47     *
48     * Add operation is not supported in this implementation, and
49     * UnsupportedOperationException will always be thrown out.
50     *
51     * @param object
52     *            the element to be added.
53     * @return true if the collection is changed successfully after invoking
54     *         this method. Otherwise, false.
55     * @throws UnsupportedOperationException
56     *                if add operation is not supported by this class.
57     * @throws NullPointerException
58     *                if null is used to invoke this method, and null is not
59     *                permitted by this collection.
60     * @throws ClassCastException
61     *                if the class type of the specified element is not
62     *                compatible with the permitted class type.
63     * @throws IllegalArgumentException
64     *                if limitations of this collection prevent the specified
65     *                element from being added
66     */
67    public boolean add(E object) {
68        throw new UnsupportedOperationException();
69    }
70
71    /**
72     * Adds the objects in the specified Collection to this Collection.
73     *
74     * @param collection
75     *            the Collection of objects
76     * @return true if this Collection is modified, false otherwise
77     *
78     * @throws UnsupportedOperationException
79     *                when adding to this Collection is not supported
80     * @throws NullPointerException
81     *                if null is used to invoke this method
82     */
83    public boolean addAll(Collection<? extends E> collection) {
84        boolean result = false;
85        Iterator<? extends E> it = collection.iterator();
86        while (it.hasNext()) {
87            if (add(it.next())) {
88                result = true;
89            }
90        }
91        return result;
92    }
93
94    /**
95     * Removes all the elements in this collection. This collection will be
96     * cleared up after this operation. The operation iterates over the
97     * collection, removes every element using Iterator.remove method.
98     *
99     * UnsupportedOperationException will be thrown out if the iterator returned
100     * by this collection does not implement the remove method and the collection
101     * is not zero length.
102     *
103     * @throws UnsupportedOperationException
104     *                  if this operation is not implemented.
105     */
106    public void clear() {
107        Iterator<E> it = iterator();
108        while (it.hasNext()) {
109            it.next();
110            it.remove();
111        }
112    }
113
114    /**
115     * Searches this Collection for the specified object.
116     *
117     * @param object
118     *            the object to search for
119     * @return true if <code>object</code> is an element of this Collection,
120     *         false otherwise
121     */
122    public boolean contains(Object object) {
123        Iterator<E> it = iterator();
124        if (object != null) {
125            while (it.hasNext()) {
126                if (object.equals(it.next())) {
127                    return true;
128                }
129            }
130        } else {
131            while (it.hasNext()) {
132                if (it.next() == null) {
133                    return true;
134                }
135            }
136        }
137        return false;
138    }
139
140    /**
141     * Searches this Collection for all objects in the specified Collection.
142     *
143     * @param collection
144     *            the Collection of objects
145     * @return true if all objects in the specified Collection are elements of
146     *         this Collection, false otherwise
147     * @throws NullPointerException
148     *                if null is used to invoke this method
149     */
150    public boolean containsAll(Collection<?> collection) {
151        Iterator<?> it = collection.iterator();
152        while (it.hasNext()) {
153            if (!contains(it.next())) {
154                return false;
155            }
156        }
157        return true;
158    }
159
160    /**
161     * Returns true if the collection has no element, otherwise false.
162     *
163     * @return true if the collection has no element.
164     */
165    public boolean isEmpty() {
166        return size() == 0;
167    }
168
169    /**
170     * Returns an Iterator on the elements of this Collection. A subclass must
171     * implement the abstract methods iterator() and size().
172     *
173     * @return an Iterator on the elements of this Collection
174     *
175     * @see Iterator
176     */
177    public abstract Iterator<E> iterator();
178
179    /**
180     * Removes the first occurrence of the specified object from this
181     * Collection. This operation traverses over the collection, looking
182     * for the specified object. Once the object is found, the object will
183     * be removed from the collection using the iterator's remove method.
184     *
185     * This collection will throw an UnsupportedOperationException if the
186     * iterator returned does not implement remove method, and the specified
187     * object is in this collection.
188     *
189     * @param object
190     *            the object to remove
191     * @return true if this Collection is modified, false otherwise
192     *
193     * @throws UnsupportedOperationException
194     *                when removing from this Collection is not supported
195     */
196    public boolean remove(Object object) {
197        Iterator<?> it = iterator();
198        if (object != null) {
199            while (it.hasNext()) {
200                if (object.equals(it.next())) {
201                    it.remove();
202                    return true;
203                }
204            }
205        } else {
206            while (it.hasNext()) {
207                if (it.next() == null) {
208                    it.remove();
209                    return true;
210                }
211            }
212        }
213        return false;
214    }
215
216    /**
217     * Removes all occurrences in this Collection of each object in the
218     * specified Collection. This operation traverses over the collection
219     * itself, to verify whether each element is contained in the specified
220     * collection. The object will be removed from the collection itself using
221     * the iterator's remove method if it is contained in the specified
222     * collection.
223     *
224     * This collection will throw an UnsupportedOperationException if the
225     * iterator returned does not implement remove method, and the element
226     * in the specified collection is contained in this collection.
227     *
228     * @param collection
229     *            the Collection of objects to remove
230     * @return true if this Collection is modified, false otherwise
231     *
232     * @throws UnsupportedOperationException
233     *                when removing from this Collection is not supported
234     * @throws NullPointerException
235     *                if null is used to invoke this method
236     */
237    public boolean removeAll(Collection<?> collection) {
238        boolean result = false;
239        Iterator<?> it = iterator();
240        while (it.hasNext()) {
241            if (collection.contains(it.next())) {
242                it.remove();
243                result = true;
244            }
245        }
246        return result;
247    }
248
249    /**
250     * Removes all objects from this Collection that are not contained in the
251     * specified Collection. This operation traverses over the collection
252     * itself, to verify whether any element is contained in the specified
253     * collection. The object will be removed from the collection itself using
254     * the iterator's remove method if it is not contained in the specified
255     * collection.
256     *
257     * This collection will throw an UnsupportedOperationException if the
258     * iterator returned does not implement remove method, and the collection
259     * itself does contain elements which do not exist in the specified collection.
260     *
261     * @param collection
262     *            the Collection of objects to retain
263     * @return true if this Collection is modified, false otherwise
264     *
265     * @throws UnsupportedOperationException
266     *                when removing from this Collection is not supported
267     * @throws NullPointerException
268     *                if null is used to invoke this method
269     */
270    public boolean retainAll(Collection<?> collection) {
271        boolean result = false;
272        Iterator<?> it = iterator();
273        while (it.hasNext()) {
274            if (!collection.contains(it.next())) {
275                it.remove();
276                result = true;
277            }
278        }
279        return result;
280    }
281
282    /**
283     * Returns the number of elements in this Collection.
284     *
285     * @return the number of elements in this Collection
286     */
287    public abstract int size();
288
289    /**
290     * Returns a new array containing all elements contained in this Collection.
291     * All the elements in the array will not be referenced by the collection.
292     * The elements in the returned array will be sorted to the same order as
293     * those returned by the iterator of this collection itself if the collection
294     * guarantees the order.
295     *
296     * @return an array of the elements from this Collection
297     */
298    public Object[] toArray() {
299        int size = size(), index = 0;
300        Iterator<?> it = iterator();
301        Object[] array = new Object[size];
302        while (index < size) {
303            array[index++] = it.next();
304        }
305        return array;
306    }
307
308    /**
309     * Returns an array containing all elements contained in this Collection. If
310     * the specified array is large enough to hold the elements, the specified
311     * array is used, otherwise an array of the same type is created. If the
312     * specified array is used and is larger than this Collection, the array
313     * element following the collection elements is set to null.
314     *
315     * @param contents
316     *            the array
317     * @return an array of the elements from this Collection
318     *
319     * @throws ArrayStoreException
320     *                when the type of an element in this Collection cannot be
321     *                stored in the type of the specified array
322     * @throws NullPointerException
323     *                if null is used to invoke this method
324     */
325    @SuppressWarnings("unchecked")
326    public <T> T[] toArray(T[] contents) {
327        int size = size(), index = 0;
328        if (size > contents.length) {
329            Class<?> ct = contents.getClass().getComponentType();
330            contents = (T[])Array.newInstance(ct, size);
331        }
332        for (E entry: this) {
333            contents[index++] = (T)entry;
334        }
335        if (index < contents.length) {
336            contents[index] = null;
337        }
338        return contents;
339    }
340
341    /**
342     * Returns the string representation of this Collection. The presentation
343     * has a specific format. It is enclosed by square brackets ("[]"). Elements
344     * are separated by ', ' (comma and space).
345     *
346     * @return the string representation of this Collection
347     */
348    @Override
349    public String toString() {
350        if (isEmpty()) {
351            return "[]"; //$NON-NLS-1$
352        }
353
354        StringBuilder buffer = new StringBuilder(size() * 16);
355        buffer.append('[');
356        Iterator<?> it = iterator();
357        while (it.hasNext()) {
358            Object next = it.next();
359            if (next != this) {
360                buffer.append(next);
361            } else {
362                buffer.append("(this Collection)"); //$NON-NLS-1$
363            }
364            if(it.hasNext()) {
365                buffer.append(", "); //$NON-NLS-1$
366            }
367        }
368        buffer.append(']');
369        return buffer.toString();
370    }
371}
372