Java Iterator

通用遍历模式

遍历


链表遍历

  • 如果底层基于数组,比如ArrayList,使用下标索引遍历性能最好,使用迭代器也能接受
  • 如果底层基于链表,比如LinkedList,使用迭代器遍历性能最好,但是使用下标索引不可接受

集合操作类中使用了RamdomAccess作为区分选择遍历模式

Collection.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static <T> void fill(List<? super T> list, T obj) {
int size = list.size();

if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
for (int i=0; i<size; i++)
list.set(i, obj);
} else {
ListIterator<? super T> itr = list.listIterator();
for (int i=0; i<size; i++) {
itr.next();
itr.set(obj);
}
}
}

Java5提供了通用的遍历模式foreach,无需知道内部结构,直接遍历

Iterable


foreach遍历集合实际是基于Iterable接口,集合类都实现了这一接口
自定义类只要实现这个接口也可以用foreach循环

Collection.java
1
2
3
public interface Collection<E> extends Iterable<E> {
//...
}

遍历集合时,等价于在循环中使用迭代器

Sample
1
2
3
4
5
6
7
List<String> list = Arrays.asList("foo","bar");
for(String s : list){

}
for(Iterator<String> i = list.iterator; i.hasNext()){
String s = i.next();
}

Iterable代表可以被遍历的能力,可返回具体的迭代器

Iterable.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Iterable<T> {
Iterator<T> iterator();

default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}

//Java8 可分割的迭代器,支持并行遍历
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}

Iterator


Iterator代表具体的遍历实现逻辑,核心方法只有两个hasNext判断还有没有,next取下一个数据
如果实现支持,还可以遍历时进行删除

Iterator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Iterator<E> {
boolean hasNext();

E next();


default void remove() {
throw new UnsupportedOperationException("remove");
}

default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}

迭代特性

  • 数量无关,不能提前知道总量有多少
  • 不可逆,如果没有特殊实现,Iterator一次性使用,前进后不能倒退。如果需要多次遍历,使用Iterable,可再生出新的迭代器

扩展接口ListIterator


专为list设计的迭代器

  • 支持双向遍历
  • 支持获取索引
  • 支持增删改操作
ListIterator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();

boolean hasPrevious();
E previous();

int nextIndex();
int previousIndex();

void remove();
void set(E e);
void add(E e);
}

扩展


可以使用装饰器模式改变迭代器的行为,在外部看来还是普通的迭代器,感知不到变化

动态转换类型

Guava 扩展next,获取数据后进行转换

Sample
1
Iterator<Object> newIterator = Iterators.transform(iterator, o -> o.toString().length());

循环

Guava 扩展hasNext逻辑,发现遍历结束就重新开始遍历

Sample
1
Iterator<Object> newIterator = Iterators.cycle(iterator);

拼接

Guava 将多个迭代器保存起来,扩展hasNext逻辑,发现上一个遍历完成就开始遍历下一个

Sample
1
Iterator<Object> newIterator = Iterators.concat(iterator1,iterator2);

过滤

Guava 扩展hasNext,调用时内部会不断执行next取数据,进行判断,直到找到满足条件的数据保存起来

Sample
1
Iterator<Object> newIterator = Iterators.filter(iterator, o -> o.toString().length() == 3);

数量限制

Guava 扩展hasNext,达到数量限制后直接返回false

Sample
1
Iterator<Object> newIterator = Iterators.limit(iterator,10);

Enumeration


早期Java的迭代接口,VectorHashTable实现此接口
Iterator方法名更简洁,并且有额外的remove方法, 因此这个接口已被取代,只作为遗留代码

Enumeration.java
1
2
3
4
5
public interface Enumeration<E> {
boolean hasMoreElements();

E nextElement();
}