【Java8新特性系列】 ArrayList 新特性示例源码详解

Java 8 中的 ArrayList 新特性示例源码详解

新特性

Java 8 中的 ArrayList 引入了一些新特性,主要包括以下几点:

  1. forEach 方法:ArrayList 实现了 Iterable 接口,可以使用 forEach 方法来对列表进行迭代操作。通过传递一个 Lambda 表达式或方法引用,可以对每个元素执行相应的操作。

  2. removeIf 方法:ArrayList 提供了 removeIf 方法,可以根据指定的条件(Predicate)删除满足条件的元素。该方法会返回一个 boolean 值,表示是否有元素被删除。

  3. replaceAll 方法:ArrayList 提供了 replaceAll 方法,可以对列表中的每个元素进行替换操作。需要传递一个 UnaryOperator 对象作为参数,该对象定义了对元素的替换规则。

  4. sort 方法:ArrayList 提供了 sort 方法,可以对列表中的元素进行排序。可以传递一个 Comparator 对象来指定排序规则,也可以使用默认的自然排序。

  5. spliterator 方法:ArrayList 实现了 Spliterator 接口,可以通过 spliterator 方法获取一个用于遍历列表的分割器。分割器将列表按照一定的规则进行拆分,可以并行地处理列表中的元素。

这些新特性使得在处理 ArrayList 时更加方便和灵活,能够更高效地进行迭代、过滤、替换和排序等操作。同时,还可以利用并行处理提高处理大量数据的性能。

示例

下面是每个新特性的代码示例和输出结果:

  1. forEach 方法:
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");

// 使用 forEach 方法遍历并打印每个元素
list.forEach(System.out::println);

输出结果:

Apple
Banana
Orange
  1. removeIf 方法:
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);

// 删除偶数
numbers.removeIf(n -> n % 2 == 0);

System.out.println(numbers);

输出结果:

[1, 3, 5]
  1. replaceAll 方法:
ArrayList<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

// 将所有名字转换为大写
names.replaceAll(String::toUpperCase);

System.out.println(names);

输出结果:

[ALICE, BOB, CHARLIE]
  1. sort 方法:
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(3);
numbers.add(1);
numbers.add(4);
numbers.add(2);

// 对数字进行排序
numbers.sort(Comparator.naturalOrder());

System.out.println(numbers);

输出结果:

[1, 2, 3, 4, 5]
  1. spliterator 方法:
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");

// 获取分割器
Spliterator<String> spliterator = list.spliterator();

// 遍历并打印每个元素
spliterator.forEachRemaining(System.out::println);

输出结果:

Apple
Banana
Orange

方法总结

Java 8 中 ArrayList 类引入了一些新的方法,并且对一些已有的方法进行了改进。下面总结了 Java 8 中 ArrayList 的所有方法及其用法:

  1. forEach(Consumer<? super E> action):使用指定的操作(Lambda 表达式或方法引用)对列表中的每个元素执行操作。

  2. removeIf(Predicate<? super E> filter):根据给定的条件(Predicate)删除满足条件的元素。

  3. replaceAll(UnaryOperator<E> operator):使用指定的运算符(UnaryOperator)替换列表中的每个元素。

  4. sort(Comparator<? super E> c):使用指定的比较器(Comparator)对列表中的元素进行排序。

  5. spliterator():返回一个 Spliterator 对象,用于遍历列表中的元素。

  6. isEmpty():判断列表是否为空。

  7. size():返回列表中的元素个数。

  8. contains(Object o):判断列表是否包含指定的元素。

  9. add(E e):将指定的元素添加到列表的末尾。

  10. addAll(Collection<? extends E> c):将指定集合中的所有元素添加到列表的末尾。

  11. get(int index):返回列表中指定索引处的元素。

  12. set(int index, E element):将列表中指定索引处的元素替换为指定的元素。

  13. remove(int index):移除列表中指定索引处的元素。

  14. clear():清空列表中的所有元素。

  15. indexOf(Object o):返回列表中第一次出现指定元素的索引。

  16. lastIndexOf(Object o):返回列表中最后一次出现指定元素的索引。

  17. subList(int fromIndex, int toIndex):返回一个从 fromIndex(包含)到 toIndex(不包含)的子列表。

  18. toArray():将列表转换为数组。

  19. toArray(T[] a):将列表转换为指定类型的数组。

中文源码

/**
 * <tt>List</tt>接口的可调整大小的数组实现。实现了所有可选的列表操作,并允许包括<tt>null</tt>在内的所有元素。
 * 除了实现<tt>List</tt>接口外,这个类还提供了一些用于操作内部存储列表的数组大小的方法。(这个类与<tt>Vector</tt>大致等效,但是它是非同步的。)
 *
 * <p><tt>size</tt>、<tt>isEmpty</tt>、<tt>get</tt>、<tt>set</tt>、<tt>iterator</tt>和<tt>listIterator</tt>操作的时间复杂度为常数。
 * <tt>add</tt>操作的<i>平摊常数时间</i>,即添加n个元素需要O(n)的时间。其他所有操作的时间复杂度为线性时间(粗略来说)。
 * 与<tt>LinkedList</tt>实现相比,常数因子较低。
 *
 * <p>每个<tt>ArrayList</tt>实例都有一个<i>容量</i>。容量是用于存储列表中的元素的数组的长度。它始终至少与列表的大小相同。
 * 当元素添加到ArrayList中时,其容量会自动增长。增长策略的详细信息未指定,只保证添加元素具有恒定的平摊时间成本。
 *
 * <p>应用程序可以在添加大量元素之前使用<tt>ensureCapacity</tt>操作来增加<tt>ArrayList</tt>实例的容量。
 * 这样可以减少逐渐增加的重新分配的数量。
 *
 * <p><strong>请注意,这个实现不是同步的。</strong>
 * 如果多个线程同时访问一个<tt>ArrayList</tt>实例,并且至少有一个线程对列表进行结构性修改,那么必须在外部同步它。
 * (结构性修改是指添加或删除一个或多个元素,或者显式地调整支持数组的大小;仅仅设置元素的值不是结构性修改。)
 * 这通常通过在自然封装列表的某个对象上同步实现。
 *
 * 如果没有这样的对象存在,则应该使用{@link Collections#synchronizedList Collections.synchronizedList}方法对列表进行"包装"。
 * 最好在创建时进行包装,以防止意外的非同步访问列表:<pre>
 *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
 *
 * <p><a name="fail-fast">
 * 由该类的{@link #iterator() iterator}和{@link #listIterator(int) listIterator}方法返回的迭代器是<em>快速失败的</em>:</a>
 * 如果在创建迭代器之后的任何时间,以除了通过迭代器自己的{@link ListIterator#remove() remove}或{@link ListIterator#add(Object) add}方法之外的任何方式结构性修改了列表,迭代器将抛出一个{@link ConcurrentModificationException}。
 * 因此,在并发修改的情况下,迭代器会快速而干净地失败,而不是在未来的某个不确定的时间冒险产生任意的、非确定性的行为。
 *
 * <p>请注意,由于在存在非同步的并发修改时,无法做出任何硬性保证,因此无法保证迭代器的快速失败行为。快速失败迭代器尽力抛出{@code ConcurrentModificationException}。
 * 因此,编写依赖于此异常的正确程序是错误的:<i>迭代器的快速失败行为只应用于检测错误。</i>
 *
 * <p>这个类是Java集合框架的成员。
 *
 * @author  Josh Bloch
 * @see     Collection
 * @see     List
 * @see     LinkedList
 * @see     Vector
 * @since   1.2
 */
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认初始容量。
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 用于空实例的共享空数组实例。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 用于默认大小的空实例的共享空数组实例。我们将其与EMPTY_ELEMENTDATA区分开来,以便知道在添加第一个元素时要扩充多少。
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存储ArrayList元素的数组缓冲区。ArrayList的容量是该数组缓冲区的长度。
     * 任何带有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都会在添加第一个元素时扩展到DEFAULT_CAPACITY。
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * ArrayList的大小(它包含的元素数)。
     *
     * @serial
     */
    private int size;

    /**
     * 构造具有指定初始容量的空列表。
     *
     * @param  initialCapacity  列表的初始容量
     * @throws IllegalArgumentException 如果指定的初始容量为负数
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     * 构造一个初始容量为10的空列表。
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 构造一个包含指定集合的元素,并按集合的迭代器返回元素的顺序排列。
     *
     * @param c 要将其元素放入此列表中的集合
     * @throws NullPointerException 如果指定的集合为空
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray 可能(不正确地)不返回 Object[] (参见 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 替换为空数组。
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 将<tt>ArrayList</tt>实例的容量削减为列表的当前大小。应用程序可以使用此操作来最小化<tt>ArrayList</tt>实例的存储。
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

    /**
     * 如果需要,增加此<tt>ArrayList</tt>实例的容量,以确保它至少可以容纳由最小容量参数指定的元素数。
     *
     * @param   minCapacity   所需的最小容量
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // 非默认元素表时,任何大小都可以
            ? 0
            // 默认空表比默认大小大。已经预计是默认大小。
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 溢出感知代码
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 分配数组的最大大小。
     * 一些虚拟机在数组中保留了一些头词。尝试分配更大的数组可能导致OutOfMemoryError:请求的数组大小超过VM限制
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 增加容量以确保其至少可以容纳由最小容量参数指定的元素数。
     *
     * @param minCapacity 所需的最小容量
     */
    private void grow(int minCapacity) {
        // 溢出感知代码
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity通常接近size,所以这是一个胜利:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // 溢出
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    /**
     * 返回此列表中的元素数。
     *
     * @return 列表中的元素数
     */
    public int size() {
        return size;
    }

    /**
     * 如果此列表不包含任何元素,则返回<tt>true</tt>。
     *
     * @return 如果此列表不包含任何元素,则返回<tt>true</tt>
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 返回<tt>true</tt>如果此列表包含指定的元素。
     * 更正式地说,当且仅当此列表包含至少一个元素<tt>e</tt>,使得
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>时返回<tt>true</tt>。
     *
     * @param o 在此列表中进行存在测试的元素
     * @return 如果此列表包含指定的元素,则返回<tt>true</tt>
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    /**
     * 返回指定元素在此列表中第一次出现的索引;如果此列表不包含该元素,则返回-1。
     * 更正式地说,返回最低索引<tt>i</tt>,使得
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>;
     * 如果没有这样的索引,则返回-1。
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 返回指定元素在此列表中最后一次出现的索引;如果此列表不包含该元素,则返回-1。
     * 更正式地说,返回最高索引<tt>i</tt>,使得
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>;
     * 如果没有这样的索引,则返回-1。
     */
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 返回此<tt>ArrayList</tt>实例的浅表副本。(元素本身不会被复制。)
     *
     * @return 此<tt>ArrayList</tt>实例的克隆
     */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // 这不应该发生,因为我们是可克隆的
            throw new InternalError(e);
        }
    }
}

/**
 * 返回一个包含列表所有元素的数组,按照从第一个元素到最后一个元素的顺序排列。
 *
 * <p>返回的数组是“安全”的,因为该列表不会保留对它的引用。换句话说,这个方法必须分配一个新的数组。
 * 调用者可以自由地修改返回的数组。
 *
 * <p>该方法充当基于数组和基于集合的API之间的桥梁。
 *
 * @return 包含列表所有元素的数组,按照正确的顺序排序
 */
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

/**
 * 返回一个包含列表所有元素的数组,按照从第一个元素到最后一个元素的顺序排列;
 * 返回的数组的运行时类型与指定数组的类型相同。如果列表适应指定的数组,则返回其中。
 * 否则,将分配一个具有指定数组的运行时类型和该列表大小的新数组。
 *
 * <p>如果列表适应指定的数组并且还有多余的空间(即数组比列表的元素多),
 * 则紧随集合结束的数组中的元素将设置为 null。
 * (仅当调用者知道列表不包含任何 null 元素时,才能使用此功能来确定列表的长度。)
 *
 * @param a 要存储列表元素的数组,如果足够大;否则,将为此目的分配一个具有相同运行时类型的新数组。
 * @return 包含列表元素的数组
 * @throws ArrayStoreException 如果指定数组的运行时类型不是该列表中每个元素的超类型
 * @throws NullPointerException 如果指定的数组为 null
 */
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // 创建一个具有 a 的运行时类型,但包含我的内容的新数组:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

// 位置访问操作

@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}

/**
 * 返回列表中指定位置的元素。
 *
 * @param  index 要返回的元素的索引
 * @return 列表中指定位置的元素
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

/**
 * 用指定的元素替换列表中指定位置的元素。
 *
 * @param index 要替换的元素的索引
 * @param element 要存储在指定位置的元素
 * @return 以前在指定位置的元素
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E set(int index, E element) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

/**
 * 将指定元素追加到列表的末尾。
 *
 * @param e 要追加到此列表的元素
 * @return <tt>true</tt>(根据 {@link Collection#add} 的规定)
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 增加 modCount!
    elementData[size++] = e;
    return true;
}

/**
 * 在列表的指定位置插入指定的元素。将当前在该位置的元素(如果有)和任何后续元素向右移动(索引增加一)。
 *
 * @param index 要插入指定元素的索引
 * @param element 要插入的元素
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // 增加 modCount!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

/**
 * 删除列表中指定位置的元素。将任何后续元素向左移动(索引减少一)。
 *
 * @param index 要删除的元素的索引
 * @return 从列表中删除的元素
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // 清除以便 GC 完成工作

    return oldValue;
}

/**
 * 从列表中删除首次出现的指定元素(如果存在)。如果列表不包含该元素,则不进行更改。
 * 更正式地说,删除具有最低索引的元素 i,使得
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
 * (如果存在这样的元素)。如果此列表包含指定的元素(或等效地,如果此列表因调用而更改),则返回 <tt>true</tt>。
 *
 * @param o 要从列表中删除的元素(如果存在)
 * @return 如果列表包含指定的元素,则为 <tt>true</tt>
 */
public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

/*
 * 跳过边界检查并且不返回被移除的值的私有 remove 方法。
 */
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // 清除以便 GC 完成工作
}

/**
 * 从列表中删除所有元素。此调用返回后,列表将为空。
 */
public void clear() {
    modCount++;

    // 清除以便 GC 完成工作
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

/**
 * 按照指定集合的迭代器返回顺序,将指定集合中的所有元素追加到列表的末尾。
 * 如果在操作进行时修改了指定的集合,则该操作的行为是不确定的。
 * (这意味着如果指定的集合是此列表,且此列表不为空,则此调用的行为是不确定的。)
 *
 * @param c 包含要添加到此列表中的元素的集合
 * @return 如果此调用导致列表发生更改,则为 <tt>true</tt>
 * @throws NullPointerException 如果指定的集合为 null
 */
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // 增加 modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

/**
 * 将指定集合中的所有元素插入到此列表中的指定位置。
 * 将当前在该位置的元素(如果有)和任何后续元素向右移动(增加它们的索引)。
 * 新元素将按照指定集合的迭代器返回顺序出现在列表中。
 *
 * @param index 从指定集合中插入第一个元素的索引
 * @param c 包含要添加到此列表中的元素的集合
 * @return 如果此调用导致列表发生更改,则为 <tt>true</tt>
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * @throws NullPointerException 如果指定的集合为 null
 */
public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // 增加 modCount

    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

/**
 * 从列表中删除索引位于 {@code fromIndex}(包括)和 {@code toIndex}(不包括)之间的所有元素。
 * 将任何后续元素向左移动(减少它们的索引)。
 * 此调用通过 {@code (toIndex - fromIndex)} 个元素缩短列表。
 * (如果 {@code toIndex==fromIndex},则此操作没有效果。)
 *
 * @throws IndexOutOfBoundsException 如果 {@code fromIndex} 或 {@code toIndex} 超出范围
 *         ({@code fromIndex < 0 ||
 *          fromIndex >= size() ||
 *          toIndex > size() ||
 *          toIndex < fromIndex})
 */
protected void removeRange(int fromIndex, int toIndex) {
    modCount++;
    int numMoved = size - toIndex;
    System.arraycopy(elementData, toIndex, elementData, fromIndex,
                     numMoved);

    // 清除以便 GC 完成工作
    int newSize = size - (toIndex-fromIndex);
    for (int i = newSize; i < size; i++) {
        elementData[i] = null;
    }
    size = newSize;
}

/**
 * 检查给定的索引是否在范围内。如果不是,则抛出适当的运行时异常。
 * 此方法不检查索引是否为负:它始终在数组访问之前立即使用,
 * 如果索引为负,则会抛出 ArrayIndexOutOfBoundsException 异常。
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
 * add 和 addAll 方法使用的 rangeCheck 的版本。
 */
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
 * 构造一个 IndexOutOfBoundsException 的详细消息。
 * 在错误处理代码的许多可能重构中,此“概述”在服务器和客户端 VM 中的性能最佳。
 */
private String outOfBoundsMsg(int index) {
    return "Index: "+index+", Size: "+size;
}

/**
 * 从列表中删除包含在指定集合中的所有元素。
 *
 * @param c 包含要从此列表中删除的元素的集合
 * @return 如果此调用导致列表发生更改,则为 {@code true}
 * @throws ClassCastException 如果此列表的某个元素的类与指定集合不兼容
 * (<a href="Collection.html#optional-restrictions">可选</a>)
 * @throws NullPointerException 如果此列表包含 null 元素且指定的集合不允许 null 元素
 * (<a href="Collection.html#optional-restrictions">可选</a>),
 *         或者指定的集合为 null
 * @see Collection#contains(Object)
 */
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

/**
 * 保留列表中与指定集合中的元素相同的元素,删除列表中不在指定集合中的元素。
 *
 * @param c 包含要保留在此列表中的元素的集合
 * @return 如果调用导致列表发生更改,则为 {@code true}
 * @throws ClassCastException 如果此列表的某个元素的类与指定集合不兼容
 * (<a href="Collection.html#optional-restrictions">可选</a>)
 * @throws NullPointerException 如果此列表包含 null 元素且指定的集合不允许 null 元素
 * (<a href="Collection.html#optional-restrictions">可选</a>),
 *         或者指定的集合为 null
 * @see Collection#contains(Object)
 */
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}

private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}

/**
 * 保存 <tt>ArrayList</tt> 实例的状态到流中(即序列化)。
 *
 * @serialData 序列化时会先写出数组的长度(int),然后按照正确顺序写出所有元素(每个元素为 <tt>Object</tt> 类型)。
 */
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // 先写出元素数量,和其他隐藏信息
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // 写出容量作为行为兼容性与 clone() 方法
    s.writeInt(size);

    // 按照正确的顺序写出所有元素
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

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

/**
 * 从流中重新构建 <tt>ArrayList</tt> 实例(即反序列化)。
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // 读入大小和其他隐藏信息
    s.defaultReadObject();

    // 读入容量
    s.readInt(); // ignored

    if (size > 0) {
        // 和 clone() 方法一样,基于大小而不是容量分配数组
        int capacity = calculateCapacity(elementData, size);
        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // 按照正确的顺序读入所有元素
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

/**
 * 返回从指定 {@code fromIndex}(包括)到 {@code toIndex}(不包括)之间的子列表视图。
 * (如果 {@code fromIndex} 和 {@code toIndex} 相等,则返回的列表为空。)
 * 返回的列表由此列表支持,因此返回列表中的非结构性更改将反映在此列表中,反之亦然。
 * 返回的列表支持所有可选的列表操作。
 *
 * <p>这个方法消除了对显式范围操作(常用于数组)的需求。
 * 通过传递一个子列表视图而不是整个列表,可以将任何期望列表的操作作为范围操作使用。
 * 例如,以下习惯用法从列表中删除一系列元素:
 * <pre>
 *      list.subList(from, to).clear();
 * </pre>
 * 类似的习惯用法可以应用于 {@link #indexOf(Object)} 和 {@link #lastIndexOf(Object)},
 * 并且 {@link Collections} 类中的所有算法都可以应用于子列表。
 *
 * <p>如果在返回列表的同时修改了支持列表(即此列表),则此方法返回的列表的语义将变为未定义。
 * (结构性修改是那些改变此列表的大小,或以其他方式打扰它以使迭代产生不正确结果的修改。)
 *
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * @throws IllegalArgumentException {@inheritDoc}
 */
public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

static void subListRangeCheck(int fromIndex, int toIndex, int size) {
    if (fromIndex < 0)
        throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
    if (toIndex > size)
        throw new IndexOutOfBoundsException("toIndex = " + toIndex);
    if (fromIndex > toIndex)
        throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                           ") > toIndex(" + toIndex + ")");
}

private class SubList extends AbstractList<E> implements RandomAccess {
    private final AbstractList<E> parent;
    private final int parentOffset;
    private final int offset;
    int size;

    SubList(AbstractList<E> parent,
            int offset, int fromIndex, int toIndex) {
        this.parent = parent;
        this.parentOffset = fromIndex;
        this.offset = offset + fromIndex;
        this.size = toIndex - fromIndex;
        this.modCount = ArrayList.this.modCount;
    }

    public E set(int index, E e) {
        rangeCheck(index);
        checkForComodification();
        E oldValue = ArrayList.this.elementData(offset + index);
        ArrayList.this.elementData[offset + index] = e;
        return oldValue;
    }

    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return ArrayList.this.elementData(offset + index);
    }

    public int size() {
        checkForComodification();
        return this.size;
    }

    public void add(int index, E e) {
        rangeCheckForAdd(index);
        checkForComodification();
        parent.add(parentOffset + index, e);
        this.modCount = parent.modCount;
        this.size++;
    }

    public E remove(int index) {
        rangeCheck(index);
        checkForComodification();
        E result = parent.remove(parentOffset + index);
        this.modCount = parent.modCount;
        this.size--;
        return result;
    }

    protected void removeRange(int fromIndex, int toIndex) {
        checkForComodification();
        parent.removeRange(parentOffset + fromIndex,
                           parentOffset + toIndex);
        this.modCount = parent.modCount;
        this.size -= toIndex - fromIndex;
    }

    public boolean addAll(Collection<? extends E> c) {
        return addAll(this.size, c);
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        int cSize = c.size();
        if (cSize==0)
            return false;

        checkForComodification();
        parent.addAll(parentOffset + index, c);
        this.modCount = parent.modCount;
        this.size += cSize;
        return true;
    }

    public Iterator<E> iterator() {
        return listIterator();
    }

    public ListIterator<E> listIterator(final int index) {
        checkForComodification();
        rangeCheckForAdd(index);
        final int offset = this.offset;

        return new ListIterator<E>() {
            int cursor = index;
            int lastRet = -1;
            int expectedModCount = ArrayList.this.modCount;

            public boolean hasNext() {
                return cursor != SubList.this.size;
            }

            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= SubList.this.size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (offset + i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[offset + (lastRet = i)];
            }

            public boolean hasPrevious() {
                return cursor != 0;
            }

            @SuppressWarnings("unchecked")
            public E previous() {
                checkForComodification();
                int i = cursor - 1;
                if (i < 0)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (offset + i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i;
                return (E) elementData[offset + (lastRet = i)];
            }

            @SuppressWarnings("unchecked")
            public void forEachRemaining(Consumer<? super E> consumer) {
                Objects.requireNonNull(consumer);
                final int size = SubList.this.size;
                int i = cursor;
                if (i >= size) {
                    return;
                }
                final Object[] elementData = ArrayList.this.elementData;
                if (offset + i >= elementData.length) {
                    throw new ConcurrentModificationException();
                }
                while (i != size && modCount == expectedModCount) {
                    consumer.accept((E) elementData[offset + (i++)]);
                }
                // update once at end of iteration to reduce heap write traffic
                lastRet = cursor = i;
                checkForComodification();
            }

            public int nextIndex() {
                return cursor;
            }

            public int previousIndex() {
                return cursor - 1;
            }

            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();

                try {
                    SubList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = ArrayList.this.modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

            public void set(E e) {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();

                try {
                    ArrayList.this.set(offset + lastRet, e);
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

            public void add(E e) {
                checkForComodification();

                try {
                    int i = cursor;
                    SubList.this.add(i, e);
                    cursor = i + 1;
                    lastRet = -1;
                    expectedModCount = ArrayList.this.modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

            final void checkForComodification() {
                if (expectedModCount != ArrayList.this.modCount)
                    throw new ConcurrentModificationException();
            }
        };
    }

    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, offset, fromIndex, toIndex);
    }

    private void rangeCheck(int index) {
        if (index < 0 || index >= this.size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private void rangeCheckForAdd(int index) {
        if (index < 0 || index > this.size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+this.size;
    }

    private void checkForComodification() {
        if (ArrayList.this.modCount != this.modCount)
            throw new ConcurrentModificationException();
    }

    public Spliterator<E> spliterator() {
        checkForComodification();
        return new ArrayListSpliterator<E>(ArrayList.this, offset,
                                           offset + this.size, this.modCount);
    }
}

@Override
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

/**
 * 创建一个 <em><a href="Spliterator.html#binding">延迟绑定</a></em>
 * 且 <em>快速失败</em> 的 {@link Spliterator},用于遍历此列表中的元素。
 *
 * <p>{@code Spliterator} 报告 {@link Spliterator#SIZED}、
 * {@link Spliterator#SUBSIZED} 和 {@link Spliterator#ORDERED} 特性。
 * 覆盖实现应该记录额外特性值的报告。
 *
 * @return 在此列表中的元素上的 {@code Spliterator}
 * @since 1.8
 */
@Override
public Spliterator<E> spliterator() {
    return new ArrayListSpliterator<>(this, 0, -1, 0);
}

/** 基于索引的拆分为两半,延迟初始化 Spliterator */
static final class ArrayListSpliterator<E> implements Spliterator<E> {

    /*
     * 如果 ArrayList 是不可变的,或者结构上不可变(没有添加、删除等操作),
     * 我们可以使用 Arrays.spliterator 来实现它们的分割器。
     * 相反,我们在尽量不牺牲性能的情况下检测遍历过程中的干扰。
     * 我们主要依赖于 modCount。这些并不能保证检测到并发冲突,
     * 并且有时对于线程内部干扰的判断过于保守,
     * 但是能够检测到足够多的问题,在实践中是值得的。
     * 为了执行这个任务,我们采取以下策略:
     * (1) 直到最后需要将其与正在检查的状态提交时才延迟初始化 fence 和 expectedModCount;
     * 从而提高精度。(对于创建具有当前非懒惰值的 SubList 来说,这不适用)
     * (2) 我们仅在 forEach(最重要的方法)的末尾执行一次 ConcurrentModificationException 检查。
     * 当使用 forEach(而不是迭代器)时,我们通常只能在执行操作之后检测到干扰,而不是之前。
     * 进一步的 CME 检查适用于所有其他可能违反假设的情况,
     * 例如给定其 size() 的 null 或太小的 elementData 数组,只能由于干扰而发生。
     * 这样可以使 forEach 的内部循环运行而不需要进一步的检查,并简化了 lambda 解析。
     * 尽管这涉及到了许多检查,但请注意,在常见情况下 list.stream().forEach(a) 中,
     * 除了在 forEach 本身内部,没有任何检查或其他计算发生。
     * 其他较少使用的方法无法利用这些优化。
     */

    private final ArrayList<E> list;
    private int index; // 当前索引,通过 advance/split 进行修改
    private int fence; // -1 直到使用为止;然后是最后一个索引的下一个位置
    private int expectedModCount; // 在设置 fence 时初始化

    /** 创建一个新的分割器,覆盖给定范围 */
    ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                         int expectedModCount) {
        this.list = list; // 如果未遍历,则可以为 null
        this.index = origin;
        this.fence = fence;
        this.expectedModCount = expectedModCount;
    }

    private int getFence() { // 在第一次使用时将 fence 初始化为 size
        int hi; // (一个专门的变体出现在 forEach 方法中)
        ArrayList<E> lst;
        if ((hi = fence) < 0) {
            if ((lst = list) == null)
                hi = fence = 0;
            else {
                expectedModCount = lst.modCount;
                hi = fence = lst.size;
            }
        }
        return hi;
    }

    public ArrayListSpliterator<E> trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid) ? null : // 除非范围太小,否则将范围一分为二
            new ArrayListSpliterator<E>(list, lo, index = mid,
                                        expectedModCount);
    }

    public boolean tryAdvance(Consumer<? super E> action) {
        if (action == null)
            throw new NullPointerException();
        int hi = getFence(), i = index;
        if (i < hi) {
            index = i + 1;
            @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
            action.accept(e);
            if (list.modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return true;
        }
        return false;
    }

    public void forEachRemaining(Consumer<? super E> action) {
        int i, hi, mc; // 将访问和检查从循环中提取出来
        ArrayList<E> lst; Object[] a;
        if (action == null)
            throw new NullPointerException();
        if ((lst = list) != null && (a = lst.elementData) != null) {
            if ((hi = fence) < 0) {
                mc = lst.modCount;
                hi = lst.size;
            }
            else
                mc = expectedModCount;
            if ((i = index) >= 0 && (index = hi) <= a.length) {
                for (; i < hi; ++i) {
                    @SuppressWarnings("unchecked") E e = (E) a[i];
                    action.accept(e);
                }
                if (lst.modCount == mc)
                    return;
            }
        }
        throw new ConcurrentModificationException();
    }

    public long estimateSize() {
        return (long) (getFence() - index);
    }

    public int characteristics() {
        return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
    }
}

@Override
public boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    // 找出要删除的元素
    // 在此阶段,如果过滤器断言抛出任何异常,则集合不会被修改
    int removeCount = 0;
    final BitSet removeSet = new BitSet(size);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        @SuppressWarnings("unchecked")
        final E element = (E) elementData[i];
        if (filter.test(element)) {
            removeSet.set(i);
            removeCount++;
        }
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }

    // 将剩余的元素左移以填充被删除元素的空白位置
    final boolean anyToRemove = removeCount > 0;
    if (anyToRemove) {
        final int newSize = size - removeCount;
        for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
            i = removeSet.nextClearBit(i);
            elementData[j] = elementData[i];
        }
        for (int k=newSize; k < size; k++) {
            elementData[k] = null;  // 让 GC 做它的工作
        }
        this.size = newSize;
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    return anyToRemove;
}

@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        elementData[i] = operator.apply((E) elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值