ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/ArrayList.java
(Generate patch)

Comparing jsr166/src/main/java/util/ArrayList.java (file contents):
Revision 1.18 by jsr166, Sun Mar 19 17:40:40 2006 UTC vs.
Revision 1.30 by jsr166, Sun Sep 5 21:32:19 2010 UTC

# Line 1 | Line 1
1   /*
2 < * %W% %E%
2 > * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3 > * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4   *
5 < * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
6 < * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
5 > * This code is free software; you can redistribute it and/or modify it
6 > * under the terms of the GNU General Public License version 2 only, as
7 > * published by the Free Software Foundation.  Sun designates this
8 > * particular file as subject to the "Classpath" exception as provided
9 > * by Sun in the LICENSE file that accompanied this code.
10 > *
11 > * This code is distributed in the hope that it will be useful, but WITHOUT
12 > * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 > * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 > * version 2 for more details (a copy is included in the LICENSE file that
15 > * accompanied this code).
16 > *
17 > * You should have received a copy of the GNU General Public License version
18 > * 2 along with this work; if not, write to the Free Software Foundation,
19 > * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 > *
21 > * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 > * or visit www.oracle.com if you need additional information or have any
23 > * questions.
24   */
25  
26   package java.util;
# Line 13 | Line 31 | package java.util;
31   * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
32   * this class provides methods to manipulate the size of the array that is
33   * used internally to store the list.  (This class is roughly equivalent to
34 < * <tt>Vector</tt>, except that it is unsynchronized.)<p>
34 > * <tt>Vector</tt>, except that it is unsynchronized.)
35   *
36 < * The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
36 > * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
37   * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
38   * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
39   * that is, adding n elements requires O(n) time.  All of the other operations
40   * run in linear time (roughly speaking).  The constant factor is low compared
41 < * to that for the <tt>LinkedList</tt> implementation.<p>
41 > * to that for the <tt>LinkedList</tt> implementation.
42   *
43 < * Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
43 > * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
44   * the size of the array used to store the elements in the list.  It is always
45   * at least as large as the list size.  As elements are added to an ArrayList,
46   * its capacity grows automatically.  The details of the growth policy are not
47   * specified beyond the fact that adding an element has constant amortized
48 < * time cost.<p>
48 > * time cost.
49   *
50 < * An application can increase the capacity of an <tt>ArrayList</tt> instance
50 > * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
51   * before adding a large number of elements using the <tt>ensureCapacity</tt>
52   * operation.  This may reduce the amount of incremental reallocation.
53   *
# Line 48 | Line 66 | package java.util;
66   * unsynchronized access to the list:<pre>
67   *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
68   *
69 < * <p>The iterators returned by this class's <tt>iterator</tt> and
70 < * <tt>listIterator</tt> methods are <i>fail-fast</i>: if the list is
71 < * structurally modified at any time after the iterator is created, in any way
72 < * except through the iterator's own <tt>remove</tt> or <tt>add</tt> methods,
73 < * the iterator will throw a {@link ConcurrentModificationException}.  Thus, in
74 < * the face of concurrent modification, the iterator fails quickly and cleanly,
75 < * rather than risking arbitrary, non-deterministic behavior at an undetermined
76 < * time in the future.<p>
69 > * <p><a name="fail-fast"/>
70 > * The iterators returned by this class's {@link #iterator() iterator} and
71 > * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:
72 > * if the list is structurally modified at any time after the iterator is
73 > * created, in any way except through the iterator's own
74 > * {@link ListIterator#remove() remove} or
75 > * {@link ListIterator#add(Object) add} methods, the iterator will throw a
76 > * {@link ConcurrentModificationException}.  Thus, in the face of
77 > * concurrent modification, the iterator fails quickly and cleanly, rather
78 > * than risking arbitrary, non-deterministic behavior at an undetermined
79 > * time in the future.
80   *
81 < * Note that the fail-fast behavior of an iterator cannot be guaranteed
81 > * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
82   * as it is, generally speaking, impossible to make any hard guarantees in the
83   * presence of unsynchronized concurrent modification.  Fail-fast iterators
84 < * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
84 > * throw {@code ConcurrentModificationException} on a best-effort basis.
85   * Therefore, it would be wrong to write a program that depended on this
86 < * exception for its correctness: <i>the fail-fast behavior of iterators
87 < * should be used only to detect bugs.</i><p>
86 > * exception for its correctness:  <i>the fail-fast behavior of iterators
87 > * should be used only to detect bugs.</i>
88   *
89 < * This class is a member of the
90 < * <a href="{@docRoot}/../guide/collections/index.html">
89 > * <p>This class is a member of the
90 > * <a href="{@docRoot}/../technotes/guides/collections/index.html">
91   * Java Collections Framework</a>.
92   *
93   * @author  Josh Bloch
94   * @author  Neal Gafter
95 < * @version %I%, %G%
96 < * @see     Collection
97 < * @see     List
98 < * @see     LinkedList
78 < * @see     Vector
95 > * @see     Collection
96 > * @see     List
97 > * @see     LinkedList
98 > * @see     Vector
99   * @since   1.2
100   */
101  
# Line 100 | Line 120 | public class ArrayList<E> extends Abstra
120      /**
121       * Constructs an empty list with the specified initial capacity.
122       *
123 <     * @param initialCapacity the initial capacity of the list
124 <     * @throws IllegalArgumentException if the specified initial capacity
125 <     *         is negative
123 >     * @param   initialCapacity   the initial capacity of the list
124 >     * @exception IllegalArgumentException if the specified initial capacity
125 >     *            is negative
126       */
127      public ArrayList(int initialCapacity) {
128 <        super();
128 >        super();
129          if (initialCapacity < 0)
130              throw new IllegalArgumentException("Illegal Capacity: "+
131                                                 initialCapacity);
132 <        this.elementData = new Object[initialCapacity];
132 >        this.elementData = new Object[initialCapacity];
133      }
134  
135      /**
136       * Constructs an empty list with an initial capacity of ten.
137       */
138      public ArrayList() {
139 <        this(10);
139 >        this(10);
140      }
141  
142      /**
# Line 128 | Line 148 | public class ArrayList<E> extends Abstra
148       * @throws NullPointerException if the specified collection is null
149       */
150      public ArrayList(Collection<? extends E> c) {
151 <        elementData = c.toArray();
152 <        size = elementData.length;
153 <        // c.toArray might (incorrectly) not return Object[] (see 6260652)
154 <        if (elementData.getClass() != Object[].class)
155 <            elementData = Arrays.copyOf(elementData, size, Object[].class);
151 >        elementData = c.toArray();
152 >        size = elementData.length;
153 >        // c.toArray might (incorrectly) not return Object[] (see 6260652)
154 >        if (elementData.getClass() != Object[].class)
155 >            elementData = Arrays.copyOf(elementData, size, Object[].class);
156      }
157  
158      /**
# Line 141 | Line 161 | public class ArrayList<E> extends Abstra
161       * the storage of an <tt>ArrayList</tt> instance.
162       */
163      public void trimToSize() {
164 <        modCount++;
165 <        int oldCapacity = elementData.length;
166 <        if (size < oldCapacity) {
164 >        modCount++;
165 >        int oldCapacity = elementData.length;
166 >        if (size < oldCapacity) {
167              elementData = Arrays.copyOf(elementData, size);
168 <        }
168 >        }
169      }
170  
171      /**
# Line 153 | Line 173 | public class ArrayList<E> extends Abstra
173       * necessary, to ensure that it can hold at least the number of elements
174       * specified by the minimum capacity argument.
175       *
176 <     * @param minCapacity the desired minimum capacity
176 >     * @param   minCapacity   the desired minimum capacity
177       */
178      public void ensureCapacity(int minCapacity) {
179 <        modCount++;
180 <        if (minCapacity > elementData.length)
181 <            growArray(minCapacity);
182 <    }
183 <
184 <    /**
185 <     * Increases the capacity of the array.
186 <     *
187 <     * @param minCapacity the desired minimum capacity
168 <     */
169 <    private void growArray(int minCapacity) {
170 <        if (minCapacity < 0) // overflow
171 <            throw new OutOfMemoryError();
172 <        int oldCapacity = elementData.length;
173 <        // Double size if small; else grow by 50%
174 <        int newCapacity = ((oldCapacity < 64) ?
175 <                           ((oldCapacity + 1) * 2) :
176 <                           ((oldCapacity / 2) * 3));
177 <        if (newCapacity < 0) // overflow
178 <            newCapacity = Integer.MAX_VALUE;
179 <        if (newCapacity < minCapacity)
180 <            newCapacity = minCapacity;
181 <        elementData = Arrays.copyOf(elementData, newCapacity);
179 >        modCount++;
180 >        int oldCapacity = elementData.length;
181 >        if (minCapacity > oldCapacity) {
182 >            int newCapacity = (oldCapacity * 3)/2 + 1;
183 >            if (newCapacity < minCapacity)
184 >                newCapacity = minCapacity;
185 >            // minCapacity is usually close to size, so this is a win:
186 >            elementData = Arrays.copyOf(elementData, newCapacity);
187 >        }
188      }
189  
190      /**
# Line 187 | Line 193 | public class ArrayList<E> extends Abstra
193       * @return the number of elements in this list
194       */
195      public int size() {
196 <        return size;
196 >        return size;
197      }
198  
199      /**
# Line 196 | Line 202 | public class ArrayList<E> extends Abstra
202       * @return <tt>true</tt> if this list contains no elements
203       */
204      public boolean isEmpty() {
205 <        return size == 0;
205 >        return size == 0;
206      }
207  
208      /**
# Line 209 | Line 215 | public class ArrayList<E> extends Abstra
215       * @return <tt>true</tt> if this list contains the specified element
216       */
217      public boolean contains(Object o) {
218 <        return indexOf(o) >= 0;
218 >        return indexOf(o) >= 0;
219      }
220  
221      /**
# Line 220 | Line 226 | public class ArrayList<E> extends Abstra
226       * or -1 if there is no such index.
227       */
228      public int indexOf(Object o) {
229 <        if (o == null) {
230 <            for (int i = 0; i < size; i++)
231 <                if (elementData[i]==null)
232 <                    return i;
233 <        } else {
234 <            for (int i = 0; i < size; i++)
235 <                if (o.equals(elementData[i]))
236 <                    return i;
237 <        }
238 <        return -1;
229 >        if (o == null) {
230 >            for (int i = 0; i < size; i++)
231 >                if (elementData[i]==null)
232 >                    return i;
233 >        } else {
234 >            for (int i = 0; i < size; i++)
235 >                if (o.equals(elementData[i]))
236 >                    return i;
237 >        }
238 >        return -1;
239      }
240  
241      /**
# Line 240 | Line 246 | public class ArrayList<E> extends Abstra
246       * or -1 if there is no such index.
247       */
248      public int lastIndexOf(Object o) {
249 <        if (o == null) {
250 <            for (int i = size-1; i >= 0; i--)
251 <                if (elementData[i]==null)
252 <                    return i;
253 <        } else {
254 <            for (int i = size-1; i >= 0; i--)
255 <                if (o.equals(elementData[i]))
256 <                    return i;
257 <        }
258 <        return -1;
249 >        if (o == null) {
250 >            for (int i = size-1; i >= 0; i--)
251 >                if (elementData[i]==null)
252 >                    return i;
253 >        } else {
254 >            for (int i = size-1; i >= 0; i--)
255 >                if (o.equals(elementData[i]))
256 >                    return i;
257 >        }
258 >        return -1;
259      }
260  
261      /**
# Line 259 | Line 265 | public class ArrayList<E> extends Abstra
265       * @return a clone of this <tt>ArrayList</tt> instance
266       */
267      public Object clone() {
268 <        try {
269 <            ArrayList<E> v = (ArrayList<E>) super.clone();
270 <            v.elementData = Arrays.copyOf(elementData, size);
271 <            v.modCount = 0;
272 <            return v;
273 <        } catch (CloneNotSupportedException e) {
274 <            // this shouldn't happen, since we are Cloneable
275 <            throw new InternalError();
276 <        }
268 >        try {
269 >            @SuppressWarnings("unchecked")
270 >                ArrayList<E> v = (ArrayList<E>) super.clone();
271 >            v.elementData = Arrays.copyOf(elementData, size);
272 >            v.modCount = 0;
273 >            return v;
274 >        } catch (CloneNotSupportedException e) {
275 >            // this shouldn't happen, since we are Cloneable
276 >            throw new InternalError();
277 >        }
278      }
279  
280      /**
# Line 312 | Line 319 | public class ArrayList<E> extends Abstra
319       *         this list
320       * @throws NullPointerException if the specified array is null
321       */
322 +    @SuppressWarnings("unchecked")
323      public <T> T[] toArray(T[] a) {
324          if (a.length < size)
325              // Make a new array of a's runtime type, but my contents:
326              return (T[]) Arrays.copyOf(elementData, size, a.getClass());
327 <        System.arraycopy(elementData, 0, a, 0, size);
327 >        System.arraycopy(elementData, 0, a, 0, size);
328          if (a.length > size)
329              a[size] = null;
330          return a;
# Line 324 | Line 332 | public class ArrayList<E> extends Abstra
332  
333      // Positional Access Operations
334  
335 <    /**
336 <     * Returns error message string for IndexOutOfBoundsExceptions
337 <     */
330 <    private String ioobe(int index) {
331 <        return "Index: " + index + ", Size: " + size;
335 >    @SuppressWarnings("unchecked")
336 >    E elementData(int index) {
337 >        return (E) elementData[index];
338      }
339  
340      /**
# Line 339 | Line 345 | public class ArrayList<E> extends Abstra
345       * @throws IndexOutOfBoundsException {@inheritDoc}
346       */
347      public E get(int index) {
348 <        if (index >= size)
349 <            throw new IndexOutOfBoundsException(ioobe(index));
350 <        return (E)elementData[index];
348 >        rangeCheck(index);
349 >
350 >        return elementData(index);
351      }
352  
353      /**
# Line 354 | Line 360 | public class ArrayList<E> extends Abstra
360       * @throws IndexOutOfBoundsException {@inheritDoc}
361       */
362      public E set(int index, E element) {
363 <        if (index >= size)
358 <            throw new IndexOutOfBoundsException(ioobe(index));
363 >        rangeCheck(index);
364  
365 <        E oldValue = (E) elementData[index];
366 <        elementData[index] = element;
367 <        return oldValue;
365 >        E oldValue = elementData(index);
366 >        elementData[index] = element;
367 >        return oldValue;
368      }
369  
370      /**
# Line 369 | Line 374 | public class ArrayList<E> extends Abstra
374       * @return <tt>true</tt> (as specified by {@link Collection#add})
375       */
376      public boolean add(E e) {
377 <        modCount++;
378 <        int s = size;
379 <        if (s >= elementData.length)
375 <            growArray(s + 1);
376 <        elementData[s] = e;
377 <        size = s + 1;
378 <        return true;
377 >        ensureCapacity(size + 1);  // Increments modCount!!
378 >        elementData[size++] = e;
379 >        return true;
380      }
381  
382      /**
# Line 388 | Line 389 | public class ArrayList<E> extends Abstra
389       * @throws IndexOutOfBoundsException {@inheritDoc}
390       */
391      public void add(int index, E element) {
392 <        int s = size;
393 <        if (index > s || index < 0)
394 <            throw new IndexOutOfBoundsException(ioobe(index));
395 <        modCount++;
396 <        if (s >= elementData.length)
397 <            growArray(s + 1);
398 <        System.arraycopy(elementData, index,
398 <                         elementData, index + 1, s - index);
399 <        elementData[index] = element;
400 <        size = s + 1;
392 >        rangeCheckForAdd(index);
393 >
394 >        ensureCapacity(size+1);  // Increments modCount!!
395 >        System.arraycopy(elementData, index, elementData, index + 1,
396 >                         size - index);
397 >        elementData[index] = element;
398 >        size++;
399      }
400  
401      /**
# Line 410 | Line 408 | public class ArrayList<E> extends Abstra
408       * @throws IndexOutOfBoundsException {@inheritDoc}
409       */
410      public E remove(int index) {
411 <        int s = size - 1;
412 <        if (index > s)
413 <            throw new IndexOutOfBoundsException(ioobe(index));
414 <        modCount++;
415 <        E oldValue = (E)elementData[index];
416 <        int numMoved = s - index;
417 <        if (numMoved > 0)
418 <            System.arraycopy(elementData, index + 1,
419 <                             elementData, index, numMoved);
420 <        elementData[s] = null;
421 <        size = s;
422 <        return oldValue;
411 >        rangeCheck(index);
412 >
413 >        modCount++;
414 >        E oldValue = elementData(index);
415 >
416 >        int numMoved = size - index - 1;
417 >        if (numMoved > 0)
418 >            System.arraycopy(elementData, index+1, elementData, index,
419 >                             numMoved);
420 >        elementData[--size] = null; // Let gc do its work
421 >
422 >        return oldValue;
423      }
424  
425      /**
# Line 438 | Line 436 | public class ArrayList<E> extends Abstra
436       * @return <tt>true</tt> if this list contained the specified element
437       */
438      public boolean remove(Object o) {
439 <        if (o == null) {
439 >        if (o == null) {
440 >            for (int index = 0; index < size; index++)
441 >                if (elementData[index] == null) {
442 >                    fastRemove(index);
443 >                    return true;
444 >                }
445 >        } else {
446              for (int index = 0; index < size; index++)
447 <                if (elementData[index] == null) {
448 <                    fastRemove(index);
449 <                    return true;
450 <                }
447 <        } else {
448 <            for (int index = 0; index < size; index++)
449 <                if (o.equals(elementData[index])) {
450 <                    fastRemove(index);
451 <                    return true;
452 <                }
447 >                if (o.equals(elementData[index])) {
448 >                    fastRemove(index);
449 >                    return true;
450 >                }
451          }
452 <        return false;
452 >        return false;
453      }
454  
455      /*
# Line 472 | Line 470 | public class ArrayList<E> extends Abstra
470       * be empty after this call returns.
471       */
472      public void clear() {
473 <        modCount++;
473 >        modCount++;
474  
475 <        // Let gc do its work
476 <        for (int i = 0; i < size; i++)
477 <            elementData[i] = null;
475 >        // Let gc do its work
476 >        for (int i = 0; i < size; i++)
477 >            elementData[i] = null;
478  
479 <        size = 0;
479 >        size = 0;
480      }
481  
482      /**
# Line 495 | Line 493 | public class ArrayList<E> extends Abstra
493       * @throws NullPointerException if the specified collection is null
494       */
495      public boolean addAll(Collection<? extends E> c) {
496 <        Object[] a = c.toArray();
496 >        Object[] a = c.toArray();
497          int numNew = a.length;
498 <        ensureCapacity(size + numNew);  // Increments modCount
498 >        ensureCapacity(size + numNew);  // Increments modCount
499          System.arraycopy(a, 0, elementData, size, numNew);
500          size += numNew;
501 <        return numNew != 0;
501 >        return numNew != 0;
502      }
503  
504      /**
# Line 519 | Line 517 | public class ArrayList<E> extends Abstra
517       * @throws NullPointerException if the specified collection is null
518       */
519      public boolean addAll(int index, Collection<? extends E> c) {
520 <        if (index > size || index < 0)
521 <            throw new IndexOutOfBoundsException(ioobe(index));
520 >        rangeCheckForAdd(index);
521 >
522 >        Object[] a = c.toArray();
523 >        int numNew = a.length;
524 >        ensureCapacity(size + numNew);  // Increments modCount
525  
526 <        Object[] a = c.toArray();
527 <        int numNew = a.length;
528 <        ensureCapacity(size + numNew);  // Increments modCount
529 <
529 <        int numMoved = size - index;
530 <        if (numMoved > 0)
531 <            System.arraycopy(elementData, index, elementData, index + numNew,
532 <                             numMoved);
526 >        int numMoved = size - index;
527 >        if (numMoved > 0)
528 >            System.arraycopy(elementData, index, elementData, index + numNew,
529 >                             numMoved);
530  
531          System.arraycopy(a, 0, elementData, index, numNew);
532 <        size += numNew;
533 <        return numNew != 0;
532 >        size += numNew;
533 >        return numNew != 0;
534      }
535  
536      /**
537       * Removes from this list all of the elements whose index is between
538 <     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
538 >     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
539       * Shifts any succeeding elements to the left (reduces their index).
540 <     * This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.
541 <     * (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)
540 >     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
541 >     * (If {@code toIndex==fromIndex}, this operation has no effect.)
542       *
543 <     * @param fromIndex index of first element to be removed
544 <     * @param toIndex index after last element to be removed
545 <     * @throws IndexOutOfBoundsException if fromIndex or toIndex out of
546 <     *              range (fromIndex &lt; 0 || fromIndex &gt;= size() || toIndex
547 <     *              &gt; size() || toIndex &lt; fromIndex)
543 >     * @throws IndexOutOfBoundsException if {@code fromIndex} or
544 >     *         {@code toIndex} is out of range
545 >     *         ({@code fromIndex < 0 ||
546 >     *          fromIndex >= size() ||
547 >     *          toIndex > size() ||
548 >     *          toIndex < fromIndex})
549       */
550      protected void removeRange(int fromIndex, int toIndex) {
551 <        modCount++;
552 <        int numMoved = size - toIndex;
551 >        modCount++;
552 >        int numMoved = size - toIndex;
553          System.arraycopy(elementData, toIndex, elementData, fromIndex,
554                           numMoved);
555  
556 <        // Let gc do its work
557 <        int newSize = size - (toIndex-fromIndex);
558 <        while (size != newSize)
559 <            elementData[--size] = null;
556 >        // Let gc do its work
557 >        int newSize = size - (toIndex-fromIndex);
558 >        while (size != newSize)
559 >            elementData[--size] = null;
560 >    }
561 >
562 >    /**
563 >     * Checks if the given index is in range.  If not, throws an appropriate
564 >     * runtime exception.  This method does *not* check if the index is
565 >     * negative: It is always used immediately prior to an array access,
566 >     * which throws an ArrayIndexOutOfBoundsException if index is negative.
567 >     */
568 >    private void rangeCheck(int index) {
569 >        if (index >= size)
570 >            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
571 >    }
572 >
573 >    /**
574 >     * A version of rangeCheck used by add and addAll.
575 >     */
576 >    private void rangeCheckForAdd(int index) {
577 >        if (index > size || index < 0)
578 >            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
579 >    }
580 >
581 >    /**
582 >     * Constructs an IndexOutOfBoundsException detail message.
583 >     * Of the many possible refactorings of the error handling code,
584 >     * this "outlining" performs best with both server and client VMs.
585 >     */
586 >    private String outOfBoundsMsg(int index) {
587 >        return "Index: "+index+", Size: "+size;
588 >    }
589 >
590 >    /**
591 >     * Removes from this list all of its elements that are contained in the
592 >     * specified collection.
593 >     *
594 >     * @param c collection containing elements to be removed from this list
595 >     * @return {@code true} if this list changed as a result of the call
596 >     * @throws ClassCastException if the class of an element of this list
597 >     *         is incompatible with the specified collection (optional)
598 >     * @throws NullPointerException if this list contains a null element and the
599 >     *         specified collection does not permit null elements (optional),
600 >     *         or if the specified collection is null
601 >     * @see Collection#contains(Object)
602 >     */
603 >    public boolean removeAll(Collection<?> c) {
604 >        return batchRemove(c, false);
605 >    }
606 >
607 >    /**
608 >     * Retains only the elements in this list that are contained in the
609 >     * specified collection.  In other words, removes from this list all
610 >     * of its elements that are not contained in the specified collection.
611 >     *
612 >     * @param c collection containing elements to be retained in this list
613 >     * @return {@code true} if this list changed as a result of the call
614 >     * @throws ClassCastException if the class of an element of this list
615 >     *         is incompatible with the specified collection (optional)
616 >     * @throws NullPointerException if this list contains a null element and the
617 >     *         specified collection does not permit null elements (optional),
618 >     *         or if the specified collection is null
619 >     * @see Collection#contains(Object)
620 >     */
621 >    public boolean retainAll(Collection<?> c) {
622 >        return batchRemove(c, true);
623 >    }
624 >
625 >    private boolean batchRemove(Collection<?> c, boolean complement) {
626 >        final Object[] elementData = this.elementData;
627 >        int r = 0, w = 0;
628 >        boolean modified = false;
629 >        try {
630 >            for (; r < size; r++)
631 >                if (c.contains(elementData[r]) == complement)
632 >                    elementData[w++] = elementData[r];
633 >        } finally {
634 >            // Preserve behavioral compatibility with AbstractCollection,
635 >            // even if c.contains() throws.
636 >            if (r != size) {
637 >                System.arraycopy(elementData, r,
638 >                                 elementData, w,
639 >                                 size - r);
640 >                w += size - r;
641 >            }
642 >            if (w != size) {
643 >                for (int i = w; i < size; i++)
644 >                    elementData[i] = null;
645 >                modCount += size - w;
646 >                size = w;
647 >                modified = true;
648 >            }
649 >        }
650 >        return modified;
651      }
652  
653      /**
# Line 571 | Line 660 | public class ArrayList<E> extends Abstra
660       */
661      private void writeObject(java.io.ObjectOutputStream s)
662          throws java.io.IOException{
663 <        // Write out element count, and any hidden stuff
664 <        int expectedModCount = modCount;
665 <        s.defaultWriteObject();
663 >        // Write out element count, and any hidden stuff
664 >        int expectedModCount = modCount;
665 >        s.defaultWriteObject();
666  
667          // Write out array length
668          s.writeInt(elementData.length);
669  
670 <        // Write out all elements in the proper order.
671 <        for (int i=0; i<size; i++)
670 >        // Write out all elements in the proper order.
671 >        for (int i=0; i<size; i++)
672              s.writeObject(elementData[i]);
673  
674 <        if (expectedModCount != modCount) {
674 >        if (modCount != expectedModCount) {
675              throw new ConcurrentModificationException();
676          }
677  
# Line 594 | Line 683 | public class ArrayList<E> extends Abstra
683       */
684      private void readObject(java.io.ObjectInputStream s)
685          throws java.io.IOException, ClassNotFoundException {
686 <        // Read in size, and any hidden stuff
687 <        s.defaultReadObject();
686 >        // Read in size, and any hidden stuff
687 >        s.defaultReadObject();
688  
689          // Read in array length and allocate array
690          int arrayLength = s.readInt();
691          Object[] a = elementData = new Object[arrayLength];
692  
693 <        // Read in all elements in the proper order.
694 <        for (int i=0; i<size; i++)
693 >        // Read in all elements in the proper order.
694 >        for (int i=0; i<size; i++)
695              a[i] = s.readObject();
696      }
697  
609
698      /**
699 <     * Returns a list-iterator of the elements in this list (in proper
699 >     * Returns a list iterator over the elements in this list (in proper
700       * sequence), starting at the specified position in the list.
701 <     * Obeys the general contract of <tt>List.listIterator(int)</tt>.<p>
701 >     * The specified index indicates the first element that would be
702 >     * returned by an initial call to {@link ListIterator#next next}.
703 >     * An initial call to {@link ListIterator#previous previous} would
704 >     * return the element with the specified index minus one.
705 >     *
706 >     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
707       *
615     * The list-iterator is <i>fail-fast</i>: if the list is structurally
616     * modified at any time after the Iterator is created, in any way except
617     * through the list-iterator's own <tt>remove</tt> or <tt>add</tt>
618     * methods, the list-iterator will throw a
619     * <tt>ConcurrentModificationException</tt>.  Thus, in the face of
620     * concurrent modification, the iterator fails quickly and cleanly, rather
621     * than risking arbitrary, non-deterministic behavior at an undetermined
622     * time in the future.
623     *
624     * @param index index of the first element to be returned from the
625     *              list-iterator (by a call to <tt>next</tt>)
626     * @return a ListIterator of the elements in this list (in proper
627     *         sequence), starting at the specified position in the list
708       * @throws IndexOutOfBoundsException {@inheritDoc}
629     * @see List#listIterator(int)
709       */
710      public ListIterator<E> listIterator(int index) {
711 <        if (index < 0 || index > size)
712 <            throw new IndexOutOfBoundsException(ioobe(index));
713 <        return new ArrayListIterator(index);
711 >        if (index < 0 || index > size)
712 >            throw new IndexOutOfBoundsException("Index: "+index);
713 >        return new ListItr(index);
714      }
715  
716      /**
717 <     * {@inheritDoc}
717 >     * Returns a list iterator over the elements in this list (in proper
718 >     * sequence).
719 >     *
720 >     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
721 >     *
722 >     * @see #listIterator(int)
723       */
724      public ListIterator<E> listIterator() {
725 <        return new ArrayListIterator(0);
725 >        return new ListItr(0);
726      }
727  
728      /**
729       * Returns an iterator over the elements in this list in proper sequence.
730       *
731 +     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
732 +     *
733       * @return an iterator over the elements in this list in proper sequence
734       */
735      public Iterator<E> iterator() {
736 <        return new ArrayListIterator(0);
736 >        return new Itr();
737      }
738  
739      /**
740 <     * A streamlined version of AbstractList.ListItr
740 >     * An optimized version of AbstractList.Itr
741       */
742 <    final class ArrayListIterator implements ListIterator<E> {
743 <        int cursor;           // index of next element to return;
744 <        int lastRet;          // index of last element, or -1 if no such
745 <        int expectedModCount; // to check for CME
660 <
661 <        ArrayListIterator(int index) {
662 <            cursor = index;
663 <            lastRet = -1;
664 <            expectedModCount = modCount;
665 <        }
742 >    private class Itr implements Iterator<E> {
743 >        int cursor;       // index of next element to return
744 >        int lastRet = -1; // index of last element returned; -1 if no such
745 >        int expectedModCount = modCount;
746  
747 <        public boolean hasNext() {
747 >        public boolean hasNext() {
748              return cursor != size;
749 <        }
670 <
671 <        public boolean hasPrevious() {
672 <            return cursor != 0;
673 <        }
749 >        }
750  
751 <        public int nextIndex() {
752 <            return cursor;
753 <        }
751 >        @SuppressWarnings("unchecked")
752 >        public E next() {
753 >            checkForComodification();
754 >            int i = cursor;
755 >            if (i >= size)
756 >                throw new NoSuchElementException();
757 >            Object[] elementData = ArrayList.this.elementData;
758 >            if (i >= elementData.length)
759 >                throw new ConcurrentModificationException();
760 >            cursor = i + 1;
761 >            return (E) elementData[lastRet = i];
762 >        }
763  
764 <        public int previousIndex() {
765 <            return cursor - 1;
766 <        }
764 >        public void remove() {
765 >            if (lastRet < 0)
766 >                throw new IllegalStateException();
767 >            checkForComodification();
768  
683        public E next() {
769              try {
770 <                int i = cursor;
771 <                E next = get(i);
772 <                lastRet = i;
773 <                cursor = i + 1;
689 <                return next;
770 >                ArrayList.this.remove(lastRet);
771 >                cursor = lastRet;
772 >                lastRet = -1;
773 >                expectedModCount = modCount;
774              } catch (IndexOutOfBoundsException ex) {
775 <                throw new NoSuchElementException();
692 <            } finally {
693 <                if (expectedModCount != modCount)
694 <                    throw new ConcurrentModificationException();
775 >                throw new ConcurrentModificationException();
776              }
777 <        }
777 >        }
778 >
779 >        final void checkForComodification() {
780 >            if (modCount != expectedModCount)
781 >                throw new ConcurrentModificationException();
782 >        }
783 >    }
784 >
785 >    /**
786 >     * An optimized version of AbstractList.ListItr
787 >     */
788 >    private class ListItr extends Itr implements ListIterator<E> {
789 >        ListItr(int index) {
790 >            super();
791 >            cursor = index;
792 >        }
793 >
794 >        public boolean hasPrevious() {
795 >            return cursor != 0;
796 >        }
797 >
798 >        public int nextIndex() {
799 >            return cursor;
800 >        }
801 >
802 >        public int previousIndex() {
803 >            return cursor - 1;
804 >        }
805  
806 +        @SuppressWarnings("unchecked")
807          public E previous() {
808 +            checkForComodification();
809 +            int i = cursor - 1;
810 +            if (i < 0)
811 +                throw new NoSuchElementException();
812 +            Object[] elementData = ArrayList.this.elementData;
813 +            if (i >= elementData.length)
814 +                throw new ConcurrentModificationException();
815 +            cursor = i;
816 +            return (E) elementData[lastRet = i];
817 +        }
818 +
819 +        public void set(E e) {
820 +            if (lastRet < 0)
821 +                throw new IllegalStateException();
822 +            checkForComodification();
823 +
824              try {
825 <                int i = cursor - 1;
701 <                E prev = get(i);
702 <                lastRet = i;
703 <                cursor = i;
704 <                return prev;
825 >                ArrayList.this.set(lastRet, e);
826              } catch (IndexOutOfBoundsException ex) {
827 <                throw new NoSuchElementException();
707 <            } finally {
708 <                if (expectedModCount != modCount)
709 <                    throw new ConcurrentModificationException();
827 >                throw new ConcurrentModificationException();
828              }
829          }
830  
831 <        public void remove() {
832 <            if (lastRet < 0)
715 <                throw new IllegalStateException();
716 <            if (expectedModCount != modCount)
717 <                throw new ConcurrentModificationException();
718 <            ArrayList.this.remove(lastRet);
719 <            if (lastRet < cursor)
720 <                cursor--;
721 <            lastRet = -1;
722 <            expectedModCount = modCount;
723 <        }
724 <
725 <        public void set(E e) {
726 <            if (lastRet < 0)
727 <                throw new IllegalStateException();
728 <            if (expectedModCount != modCount)
729 <                throw new ConcurrentModificationException();
730 <            ArrayList.this.set(lastRet, e);
731 <            expectedModCount = modCount;
732 <        }
831 >        public void add(E e) {
832 >            checkForComodification();
833  
834 <        public void add(E e) {
835 <            if (expectedModCount != modCount)
836 <                throw new ConcurrentModificationException();
837 <            try {
738 <                ArrayList.this.add(cursor++, e);
834 >            try {
835 >                int i = cursor;
836 >                ArrayList.this.add(i, e);
837 >                cursor = i + 1;
838                  lastRet = -1;
839                  expectedModCount = modCount;
840 <            } catch (IndexOutOfBoundsException ex) {
841 <                throw new ConcurrentModificationException();
842 <            }
843 <        }
840 >            } catch (IndexOutOfBoundsException ex) {
841 >                throw new ConcurrentModificationException();
842 >            }
843 >        }
844 >    }
845 >
846 >    /**
847 >     * Returns a view of the portion of this list between the specified
848 >     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
849 >     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
850 >     * empty.)  The returned list is backed by this list, so non-structural
851 >     * changes in the returned list are reflected in this list, and vice-versa.
852 >     * The returned list supports all of the optional list operations.
853 >     *
854 >     * <p>This method eliminates the need for explicit range operations (of
855 >     * the sort that commonly exist for arrays).  Any operation that expects
856 >     * a list can be used as a range operation by passing a subList view
857 >     * instead of a whole list.  For example, the following idiom
858 >     * removes a range of elements from a list:
859 >     * <pre>
860 >     *      list.subList(from, to).clear();
861 >     * </pre>
862 >     * Similar idioms may be constructed for {@link #indexOf(Object)} and
863 >     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
864 >     * {@link Collections} class can be applied to a subList.
865 >     *
866 >     * <p>The semantics of the list returned by this method become undefined if
867 >     * the backing list (i.e., this list) is <i>structurally modified</i> in
868 >     * any way other than via the returned list.  (Structural modifications are
869 >     * those that change the size of this list, or otherwise perturb it in such
870 >     * a fashion that iterations in progress may yield incorrect results.)
871 >     *
872 >     * @throws IndexOutOfBoundsException {@inheritDoc}
873 >     * @throws IllegalArgumentException {@inheritDoc}
874 >     */
875 >    public List<E> subList(int fromIndex, int toIndex) {
876 >        subListRangeCheck(fromIndex, toIndex, size);
877 >        return new SubList(this, 0, fromIndex, toIndex);
878 >    }
879 >
880 >    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
881 >        if (fromIndex < 0)
882 >            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
883 >        if (toIndex > size)
884 >            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
885 >        if (fromIndex > toIndex)
886 >            throw new IllegalArgumentException("fromIndex(" + fromIndex +
887 >                                               ") > toIndex(" + toIndex + ")");
888 >    }
889 >
890 >    private class SubList extends AbstractList<E> implements RandomAccess {
891 >        private final AbstractList<E> parent;
892 >        private final int parentOffset;
893 >        private final int offset;
894 >        int size;
895 >
896 >        SubList(AbstractList<E> parent,
897 >                int offset, int fromIndex, int toIndex) {
898 >            this.parent = parent;
899 >            this.parentOffset = fromIndex;
900 >            this.offset = offset + fromIndex;
901 >            this.size = toIndex - fromIndex;
902 >            this.modCount = ArrayList.this.modCount;
903 >        }
904 >
905 >        public E set(int index, E e) {
906 >            rangeCheck(index);
907 >            checkForComodification();
908 >            E oldValue = ArrayList.this.elementData(offset + index);
909 >            ArrayList.this.elementData[offset + index] = e;
910 >            return oldValue;
911 >        }
912 >
913 >        public E get(int index) {
914 >            rangeCheck(index);
915 >            checkForComodification();
916 >            return ArrayList.this.elementData(offset + index);
917 >        }
918 >
919 >        public int size() {
920 >            checkForComodification();
921 >            return this.size;
922 >        }
923 >
924 >        public void add(int index, E e) {
925 >            rangeCheckForAdd(index);
926 >            checkForComodification();
927 >            parent.add(parentOffset + index, e);
928 >            this.modCount = parent.modCount;
929 >            this.size++;
930 >        }
931 >
932 >        public E remove(int index) {
933 >            rangeCheck(index);
934 >            checkForComodification();
935 >            E result = parent.remove(parentOffset + index);
936 >            this.modCount = parent.modCount;
937 >            this.size--;
938 >            return result;
939 >        }
940 >
941 >        protected void removeRange(int fromIndex, int toIndex) {
942 >            checkForComodification();
943 >            parent.removeRange(parentOffset + fromIndex,
944 >                               parentOffset + toIndex);
945 >            this.modCount = parent.modCount;
946 >            this.size -= toIndex - fromIndex;
947 >        }
948 >
949 >        public boolean addAll(Collection<? extends E> c) {
950 >            return addAll(this.size, c);
951 >        }
952 >
953 >        public boolean addAll(int index, Collection<? extends E> c) {
954 >            rangeCheckForAdd(index);
955 >            int cSize = c.size();
956 >            if (cSize==0)
957 >                return false;
958 >
959 >            checkForComodification();
960 >            parent.addAll(parentOffset + index, c);
961 >            this.modCount = parent.modCount;
962 >            this.size += cSize;
963 >            return true;
964 >        }
965 >
966 >        public Iterator<E> iterator() {
967 >            return listIterator();
968 >        }
969 >
970 >        public ListIterator<E> listIterator(final int index) {
971 >            checkForComodification();
972 >            rangeCheckForAdd(index);
973 >            final int offset = this.offset;
974 >
975 >            return new ListIterator<E>() {
976 >                int cursor = index;
977 >                int lastRet = -1;
978 >                int expectedModCount = ArrayList.this.modCount;
979 >
980 >                public boolean hasNext() {
981 >                    return cursor != SubList.this.size;
982 >                }
983 >
984 >                @SuppressWarnings("unchecked")
985 >                public E next() {
986 >                    checkForComodification();
987 >                    int i = cursor;
988 >                    if (i >= SubList.this.size)
989 >                        throw new NoSuchElementException();
990 >                    Object[] elementData = ArrayList.this.elementData;
991 >                    if (offset + i >= elementData.length)
992 >                        throw new ConcurrentModificationException();
993 >                    cursor = i + 1;
994 >                    return (E) elementData[offset + (lastRet = i)];
995 >                }
996 >
997 >                public boolean hasPrevious() {
998 >                    return cursor != 0;
999 >                }
1000 >
1001 >                @SuppressWarnings("unchecked")
1002 >                public E previous() {
1003 >                    checkForComodification();
1004 >                    int i = cursor - 1;
1005 >                    if (i < 0)
1006 >                        throw new NoSuchElementException();
1007 >                    Object[] elementData = ArrayList.this.elementData;
1008 >                    if (offset + i >= elementData.length)
1009 >                        throw new ConcurrentModificationException();
1010 >                    cursor = i;
1011 >                    return (E) elementData[offset + (lastRet = i)];
1012 >                }
1013 >
1014 >                public int nextIndex() {
1015 >                    return cursor;
1016 >                }
1017 >
1018 >                public int previousIndex() {
1019 >                    return cursor - 1;
1020 >                }
1021 >
1022 >                public void remove() {
1023 >                    if (lastRet < 0)
1024 >                        throw new IllegalStateException();
1025 >                    checkForComodification();
1026 >
1027 >                    try {
1028 >                        SubList.this.remove(lastRet);
1029 >                        cursor = lastRet;
1030 >                        lastRet = -1;
1031 >                        expectedModCount = ArrayList.this.modCount;
1032 >                    } catch (IndexOutOfBoundsException ex) {
1033 >                        throw new ConcurrentModificationException();
1034 >                    }
1035 >                }
1036 >
1037 >                public void set(E e) {
1038 >                    if (lastRet < 0)
1039 >                        throw new IllegalStateException();
1040 >                    checkForComodification();
1041 >
1042 >                    try {
1043 >                        ArrayList.this.set(offset + lastRet, e);
1044 >                    } catch (IndexOutOfBoundsException ex) {
1045 >                        throw new ConcurrentModificationException();
1046 >                    }
1047 >                }
1048 >
1049 >                public void add(E e) {
1050 >                    checkForComodification();
1051 >
1052 >                    try {
1053 >                        int i = cursor;
1054 >                        SubList.this.add(i, e);
1055 >                        cursor = i + 1;
1056 >                        lastRet = -1;
1057 >                        expectedModCount = ArrayList.this.modCount;
1058 >                    } catch (IndexOutOfBoundsException ex) {
1059 >                        throw new ConcurrentModificationException();
1060 >                    }
1061 >                }
1062 >
1063 >                final void checkForComodification() {
1064 >                    if (expectedModCount != ArrayList.this.modCount)
1065 >                        throw new ConcurrentModificationException();
1066 >                }
1067 >            };
1068 >        }
1069 >
1070 >        public List<E> subList(int fromIndex, int toIndex) {
1071 >            subListRangeCheck(fromIndex, toIndex, size);
1072 >            return new SubList(this, offset, fromIndex, toIndex);
1073 >        }
1074 >
1075 >        private void rangeCheck(int index) {
1076 >            if (index < 0 || index >= this.size)
1077 >                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
1078 >        }
1079 >
1080 >        private void rangeCheckForAdd(int index) {
1081 >            if (index < 0 || index > this.size)
1082 >                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
1083 >        }
1084 >
1085 >        private String outOfBoundsMsg(int index) {
1086 >            return "Index: "+index+", Size: "+this.size;
1087 >        }
1088 >
1089 >        private void checkForComodification() {
1090 >            if (ArrayList.this.modCount != this.modCount)
1091 >                throw new ConcurrentModificationException();
1092 >        }
1093      }
1094   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines