紧接上一篇,ArrayList中已经指定存放数据的方式是数组,那么迭代器的实现就可以更加的具体,下面我们就来看看ArrayList中的这些具体实现。
首先是获取迭代器的几个方法
iterator()
listIterator()、listIterator(final int index)
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)
public List 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)
//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 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 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 spliterator() {
return new ArrayListSpliterator<>(this, 0, -1, 0);
}
返回一个新实现的可分割迭代器,或者说是叫并行的迭代器,大大加强并行处理能力,jdk1.8中的集合框架中的数据结构都默认实现了spliterator,下一个部分我们会连同spliterator接口和ArrayListSpliterator一并细说。