前言
當我們想要遍歷集合時,Java為我們提供了多種選擇,通常有以下三種寫法:
- 寫法1:for循環(huán)
for (int i = 0, len = strings.size(); i < len; i++) {
System.out.println(strings.get(i));
}
- 寫法2:foreach循環(huán)
for (String var : strings) {
System.out.println(var);
}
- 寫法3:Iterator
Iterator iterator = strings.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
那么以上三種遍歷方式有何區(qū)別呢?for循環(huán)我們很熟悉了,就是根據(jù)下標來獲取元素,這個特性與數(shù)組十分吻合,不熟悉的朋友可以閱讀前面講解數(shù)組的文章。foreach則主要對類似鏈表的結(jié)構(gòu)提供遍歷支持,鏈表沒有下標,所以使用for循環(huán)遍歷會大大降低性能。Iterator就是我們今天要講述的主角,它實際上就是foreach。
那么,為什么集合可以進行foreach遍歷,而我們自己定義的Java對象卻不可以呢?有沒有辦法讓任何對象都支持這種遍歷方式?下面的內(nèi)容會告訴我們答案。
Iterable
Iterable是迭代器的意思,作用是為集合類提供for-each循環(huán)的支持。由于使用for循環(huán)需要通過位置獲取元素,而這種獲取方式僅有數(shù)組支持,其他許多數(shù)據(jù)結(jié)構(gòu),比如鏈表,只能通過查詢獲取數(shù)據(jù),這會大大的降低效率。Iterable就可以讓不同的集合類自己提供遍歷的最佳方式。
Iterable的文檔聲明僅有一句:
Implementing this interface allows an object to be the target of the "for-each loop" statement.
它的作用就是為Java對象提供foreach循環(huán),其主要方法是返回一個Iterator對象:
Iterator<T> iterator();
也就是說,如果想讓一個Java對象支持foreach,只要實現(xiàn)Iterable接口,然后就可以像集合那樣,通過Iterator iterator = strings.iterator()方式,或者使用foreach,進行遍歷了。
Iterator
Iterator是foreach遍歷的主體,它的代碼實現(xiàn)如下:
// 判斷一個對象集合是否還有下一個元素
boolean hasNext();
// 獲取下一個元素
E next();
// 刪除最后一個元素。默認是不支持的,因為在很多情況下其結(jié)果不可預(yù)測,比如數(shù)據(jù)集合在此時被修改
default void remove(){...}
// 主要將每個元素作為參數(shù)發(fā)給action來執(zhí)行特定操作
default void forEachRemaining(Consumer<? super E> action){...}
Iterator還有一個子接口,是為需要雙向遍歷數(shù)據(jù)時準備的,在后續(xù)分析ArrayList和LinkedList時都會看到它。它主要增加了以下幾個方法:
// 是否有前一個元素
boolean hasPrevious();
// 獲取前一個元素
E previous();
// 獲取下一個元素的位置
int nextIndex();
// 獲取前一個元素的位置
int previousIndex();
// 添加一個元素
void add(E e);
// 替換當前元素值
void set(E e);
總結(jié)
在Java中有許多特性都是通過接口來實現(xiàn)的,foreach循環(huán)也是。foreach主要是解決for循環(huán)依賴下標的問題,為高效遍歷更多的數(shù)據(jù)結(jié)構(gòu)提供了支持。如果你清楚數(shù)組和鏈表的區(qū)別,應(yīng)該就可以回答以下問題了:
for與foreach有何區(qū)別,哪個更高效?
上一篇:Java集合源碼分析之基礎(chǔ)(六):紅黑樹(RB Tree)
下一篇:Java集合源碼分析之超級接口:Collection
我是飛機醬,如果您喜歡我的文章,可以關(guān)注我~
編程之路,道阻且長。唯,路漫漫其修遠兮,吾將上下而求索。