1.Iterator

使用JDK提供的迭代接口进行Java集合的迭代:

Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            String string = iterator.next();
            //do something
        }

迭代器是一个标准化遍历各类容器里面的所有对象的方法类,它采用很典型的设计模式——迭代器模式。

通过迭代器模式可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。即遍历容器中的对象不依赖于容器内部结构,所有的内部状态都由Iterator来维护,然后采用同一种逻辑来遍历集合

在Java中,Iterator是一个接口,其主要定义了以下三个方法:

public interface Iterator {
    boolean hasNext();
    E next();
    default void remove() {
        throw new UnsupportedOperationException("remove");
}

ArrayList中Iterator的实现

通过iterator()返回迭代器

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

Itr的实现如下

private class Itr implements Iterator<E> {
        int cursor;         // 下一个元素的索引位置
        int lastRet = -1;   // 上一个元素的索引位置
        int expectedModCount = modCount;
        
        Itr() {}

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

        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];
        }

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

            try {
            	// 利用ArrayList的remove()方法删除元素
                ArrayList.this.remove(lastRet);
                // 删除后由于数组前移,当前位置为遍历的下一个元素
                cursor = lastRet;
                // 上一个元素先重置为-1,下次遍历时再重新记录
                lastRet = -1;
                // 修改expectedModCount为当前的modCount,因此用迭代器进行遍历删除不会报ConcurrentModificationException()异常
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
}

2.Iterable

Iterable是Java中的一个接口,表示可以进行迭代,其主要实现如下:

public interface Iterable<T> {
    Iterator<T> iterator();
}

可以看到,Iterable接口规定了其实现类需要重写iterator()方法,并通过该方法返回该容器的迭代器

而Collection接口继承自Iterable

public interface Collection<E> extends Iterable<E>

因此,所有实现了Collection接口的容器类都需要自己实现自己的迭代器逻辑。在外部可以使用该迭代器进行统一迭代

实现了 Iterable后,即可使用下面两种迭代方法遍历容器

Iterator it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + ",");
}

// 增强for的本质就是使用iterator,在编译时翻译成使用iterator的逻辑
for (Integer i : list) {
    System.out.print(i + ",");
}

普通for和增强for遍历的比较

下面是两种迭代方式:

for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i) + ",");
}

for (Integer i : list) {
    System.out.print(i + ",");
}

两者比较:

  • 普通for是根据下标索引来从容器中获取元素,增强for是通过迭代器来获取元素
  • 对于基于数组实现的容器,由于数组支持快速随机访问,能根据下标快速访问到元素,因此两者之间的性能差距不大。普通for要比增强for稍快一点
  • 而基于链表实现的容器,通过下标获取元素每次都要从头开始访问,性能极差。而迭代器由于记录了下一个元素的位置,因此很快就能获取下一个元素。此时增强for要比普通for快很多

RandomAccess

RandomAccess用来当标记,是一种标记接口,代表其实现类支持快速随机访问。

用处是当要实现某些算法时,会判断当前类是否实现了RandomAccess接口,会选择不同的算法。

接口RandomAccess中内容是空的,只是作为标记用。比如List下的ArrayList和LinkedList。其中ArrayList实现了RandomAccess。而LinkedList没有。我们可以利用instanceof来判断哪一个是实现了RandomAccess。分辨出两个集合。其中ArrayList使用for循环遍历快,而LinkedList使用迭代器快。那么通过分辨,不同的集合使用不同的遍历方式。

所以说RandomAccess只是一个空的,用来标记的接口。