本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/iterator
迭代器(Iterator)模式又叫游標(Cursor)模式墨闲,通常用于集合類型來提供一種順序訪問其中元素而又不必暴漏集合的內(nèi)部結(jié)構(gòu)代咸,是一種行為模式玉锌。
關(guān)于迭代器(Iterator)我想對Java Collection有過接觸的同學就不陌生共虑,所以本文也就無需舉其他例子了毛秘,看一下在Java SDK中是如何實現(xiàn)的就好了添履。
據(jù)統(tǒng)計讲竿,java.util.ArrayList
是Java SDK中使用頻率最高的類翅娶。有人說程序就是數(shù)據(jù)結(jié)構(gòu)+算法,可見數(shù)據(jù)結(jié)構(gòu)的重要性昼浦。我們在日常開發(fā)中馍资,時常跟Java集合中的各種工具類打交道,對于它們关噪,遍歷元素又是家常便飯鸟蟹,比如:
String[] strings = new String[]{"Hello,", "Java", "Design", "Patterns."};
List<String> stringList = Arrays.asList(strings);
Iterator<String> iterator = stringList.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
輸出即:
Hello, Java Design Patterns.
其中的Iterator
就是迭代器,它有兩個核心方法:
java.util.Iterator.java(不考慮Java8新增內(nèi)容)
public interface Iterator<E> {
boolean hasNext();
E next();
}
-
hasNext()
用于判斷是否還有下一個元素使兔; -
next()
用于返回下一個元素建钥,同時“看向”這個元素的再下一個元素。
我們常用的一些Java數(shù)據(jù)結(jié)構(gòu)工具:
Collection
是繼承自Iterable
虐沥,而后者的核心方法就是返回Iterator
實例的iterator()
方法(不考慮Java8增加的內(nèi)容的話):
java.lang.Iterable.java
public interface Iterable<T> {
Iterator<T> iterator();
}
所以我們平時使用的各種不同的List
熊经、Set
和Queue
的具體實現(xiàn),都能返回迭代器以便能夠?qū)λ鼈冎械脑剡M行遍歷。
以java.util.ArrayList
為例镐依,它的iterator()
方法返回的是Iterator
的其內(nèi)部類的實現(xiàn):
java.util.ArrayList.java
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 實際存儲元素的數(shù)據(jù)
transient Object[] elementData;
// 元素實際個數(shù)
private int size;
... ...
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
... ...
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
... ...
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];
}
... ...
} //End of Itr
... ...
} //End of ArrayList
其中去掉了一些代碼悉盆。ArrayList
是一種數(shù)組類型的List
,其內(nèi)部采用一個Object[]
來保存所有元素馋吗,size
用來保存一共有多少個元素焕盟。
方法iterator()
會返回一個內(nèi)部類Itr
,后者實現(xiàn)了Iterator
接口的hasNext()
和next()
方法宏粤。
既然是迭代遍歷脚翘,那么就需要有一個變量能夠記錄遍歷到哪個元素了,這里Itr.cursor
就是用來記錄迭代索引的變量绍哎。每次調(diào)用hasNext()
判斷后邊是否還有元素的時候来农,其實就是比較這個索引的值是否和size
相等;每次調(diào)用next()
返回下一個元素崇堰,其實就是返回elementData[cursor]
并讓cursor
自增以指向下一個元素沃于。
這就是迭代器模式,如果去掉各種接口和類的繼承關(guān)系海诲,簡單來說:
迭代器模式是為集合類的事物服務(wù)的繁莹,因此類關(guān)系就很好說了:一邊是集合,一邊是迭代器特幔,集合能夠返回迭代器咨演,迭代器能夠遍歷集合。 出于面向接口的更加靈活的模式設(shè)計蚯斯,集合和迭代器均有抽象層(接口或抽象類)以及具體實現(xiàn)類薄风。
最后,我們再回頭看一下本文最初的例子:
Iterator<String> iterator = stringList.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
這四行就是迭代器模式的典型用法拍嵌。iterator
可能是一個ArrayList
返回的遭赂,可能是一個HashSet
返回的,我們都不care横辆,只要獲取到迭代器撇他,我們就可以“無腦流”一路hasNext() + next()
,這就是迭代器的初衷龄糊,它為集合封裝了迭代遍歷元素的方法逆粹,留給用戶的是一套簡單易用的遍歷接口募疮。