java源码品读(8)— ArrayList(二)

紧接上一篇,ArrayList中已经指定存放数据的方式是数组,那么迭代器的实现就可以更加的具体,下面我们就来看看ArrayList中的这些具体实现。

首先是获取迭代器的几个方法

  • iterator()
  • listIterator()、listIterator(final int index)
    获取的方法跟AbstractList的获取方式几乎一致,这里源码就不再贴出,稍有不同的是ListItr的和Itr的实现方式
    以Itr的next方法为例:
public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}

获取元素的方式比AbstractList的要更加具体,其他的跟AbstractList中的套路差不多。
但是ArrayList中的Itr多实现了一个方法forEachRemaining:

@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
    Objects.requireNonNull(consumer);
    final int size = ArrayList.this.size;
    int i = cursor;
    if (i >= size) {
        return;
    }
    final Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length) {
        throw new ConcurrentModificationException();
    }
    while (i != size && modCount == expectedModCount) {
        consumer.accept((E) elementData[i++]);
    }
    //在迭代结束时更新一次,以减少堆写流量,而不是每次进行更新
    cursor = i;
    lastRet = i - 1;
    checkForComodification();
}

也就是说,ArrayList的迭代器也是支持JDK1.8的函数式编程的,支持lambda表达式

listIterator()获取的ListItr同样跟AbstractList中ListItr思路基本一致,只是获取的方式略有不用。

  • subList(int fromIndex, int toIndex)
    subList方法同样是一个自我实现的内部类
public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

与AbstractList中的subList不同的是获取元素的方式更加便捷及listIterator方法获取的迭代器同样支持1.8的函数式编程,具体的代码跟上面贴出的forEachRemaining源码几乎一致,只多一个子List中多出来的一个offset偏移量的概念。

  • forEach(Consumer<? super E> action)
    ArrayList中的forEach方法改动相对较多,或者说是更加的细化了
//Iterable中的forEach方法,只检验非空,之后便对每一个元素进行函数式的执行
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

//ArrayList中的forEach方法不仅检验了非空,还加入了list中的fail-fast机制,来确保数据的安全性
@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();
    }
}
  • sort(Comparator<? super E> c)、replaceAll(UnaryOperator<E> operator)
@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++;
}

@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++;
}

两个方法实现的方式大致相同,都在原有的基础上加入了fail-fast机制来保证在使用迭代器的时候,集合元素不发生变化。

  • removeIf(Predicate<? super E> filter)
@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];
        }
        //需要保留的元素替换完之后剩下的元素置为null
        for (int k=newSize; k < size; k++) {
            elementData[k] = null;
        }
        this.size = newSize;
        //双重检验确保数据正确性
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    return anyToRemove;
}

removeif的实现改动相对较大,Collection中的removeif使用迭代器进行删除,一旦元素被删除即使中间出现异常的情况,也不会恢复到原来为修改的样子,ArrayList中的removeif的实现类似有我们日常所用到的事务,一旦条件检验的过程中出现异常,那么会保持原集合的元素不发生改变,而且bitset的使用相当巧妙有兴趣的同学可以了解一下。

  • spliterator()
@Override
public Spliterator<E> spliterator() {
    return new ArrayListSpliterator<>(this, 0, -1, 0);
}

返回一个新实现的可分割迭代器,或者说是叫并行的迭代器,大大加强并行处理能力,jdk1.8中的集合框架中的数据结构都默认实现了spliterator,下一个部分我们会连同spliterator接口和ArrayListSpliterator一并细说。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值