源码分析之Iterable
当想要遍历集合时,Java为我们提供了多种选择,通常有以下三种写法:
- for循环
for循环,就是根据下标来获取元素,这个特性与数组十分吻合。
for (int i = 0, len = strings.size(); i < len; i++) { System.out.println(strings.get(i)); }
- foreach循环
foreach则主要对类似链表的结构提供遍历支持,链表没有下标。foreach遍历实际上使用的是Iterator. 可通过 javap -verbose Test.class 查看具体实现
for (String var : strings) { System.out.println(var); }
- Iterator
Iterator iterator = strings.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); }
Iterable
Iterable接口是Java集合框架的顶级接口。Iterable是迭代器的意思,作用是为集合类提供for-each循环的支持。也就是说,如果想让一个Java对象支持foreach,只要实现Iterable接口,然后就可以像集合那样,通过Iterator iterator = strings.iterator()
方式,或者使用foreach,进行遍历了。源码如下:
public interface Iterable<T> { // 返回一个内部元素为T类型的顺序迭代器 Iterator<T> iterator(); // 对Iterable中的元素进行指定的操作 default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } // 返回一个内部元素为T类型的并行迭代器 default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } }
Iterator
Iterator为Java中的迭代器对象,是能够对List这样的集合进行迭代遍历的底层依赖。Iterator通过以下两个方法定义了对集合迭代访问的方法,而具体的实现方式依赖于不同的实现类,具体的集合类实现Iterator接口中的方法以实现迭代。
public interface Iterator<E> { // 判断一个对象集合是否还有下一个元素 boolean hasNext(); // 获取下一个元素 E next(); // 删除最后一个元素。默认是不支持的,因为在很多情况下其结果不可预测,比如数据集合在此时被修改 default void remove(){...} // 主要将每个元素作为参数发给action来执行特定操作 default void forEachRemaining(Consumer<? super E> action){...} }
为什么不直接将hasNext(),next()方法放在Iterable接口中,其他类直接实现就可以了?
原因是有些集合类可能不止一种遍历方式,实现了Iterable的类可以再实现多个Iterator内部类,例如LinkedList中的ListItr和DescendingIterator两个内部类,就分别实现了双向遍历和逆序遍历。通过返回不同的Iterator实现不同的遍历方式,这样更加灵活。