天天看點

JDK源碼閱讀-Iterator接口概述方法Q&A如有不适之處,歡迎留言讨論

概述

檢視Collection接口的定義,發現其繼承了Iterable接口,而後者又聚合了一個成員類,即Iterator。是以就先瞅瞅這個接口的定義細節。

Iterator,即我們常用的疊代器,取代了老式的Enumeration。能夠允許我們在不了解集合序列的底層結構時,輕松周遊并操作序列中的對象。因為建立代價小,是以疊代器也被視為“輕量級”對象。JDK8源碼中Iterator接口隻包含了4個方法:

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());
    }
}
           

方法

next()方法

通過反複調用next方法,可以逐個通路集合中的每個元素。但是,如果到達了集合的末尾,next方法将抛出一個

NoSuchElementException

異常。是以next方法需要配合hasNext方法使用。

Iterator疊代器的查找操作和位置變更時緊密聯系的。查找一個元素的唯一方法就是調用next,而在執行查找操作的同時,疊代器的位置随之向前移動。是以,應該将java疊代器認為是位于兩個元素之間。當調用next時,疊代器就越過下一個元素,并傳回剛剛越過的那個元素的引用。 – 《java核心技術》
JDK源碼閱讀-Iterator接口概述方法Q&amp;A如有不适之處,歡迎留言讨論

hasNext()方法

hasNext主要是用來判斷目前疊代器是否還有元素可供通路,以避免上述next方法抛出異常。

remove()方法

用來删除上次調用next方法傳回的元素。值得注意的是,next方法和remove方法的調用具有互相依賴的關系。如果調用remove之前沒有調用next方法将會抛出

IlleagalStateException

異常。通俗來講,如果想remove一個元素,則必須先用hasNext判斷疊代器是否還有元素可删,如果有則必須再調用next方法“越過”這個元素,最後删除剛剛“越過”的元素。是以,開發時,存在想删除兩個元素,就一口氣連續調用兩次remove方法,明顯就是錯誤的做法。如下:

--------------Error----------
it.remove();
it.remove(); 連續調用兩次remove,Eorror

-------------Correct---------
it.remove();
it.next();
it.remove();
           

舉例:周遊List

public static void main(String[] args) {
        List<String> xxBrothers = new ArrayList<>();
        xxBrothers.add("王寶強");
        xxBrothers.add("陳羽凡");
        xxBrothers.add("賈乃亮");
        Iterator<String> it = xxBrothers.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
            it.remove();
        }
        System.out.println(xxBrothers.size());
    }
    
---------output---------
王寶強
陳羽凡
賈乃亮
0
           

源碼中方法的定義:

default void remove() { // 使用了JDK8的預設方法的新特性
    throw new UnsupportedOperationException("remove");
}
           

forEachRemaining(Consumer)方法

forEachRemaining是在JDK1.8添加的方法,其特點是:Lambda表達式結合疊代器周遊集合嗎。其實作如下:

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

周遊List集合:

public static void main(String[] args) {
    List<String> xxBrothers = new ArrayList<>();
    xxBrothers.add("王寶強");
    xxBrothers.add("陳羽凡");
    xxBrothers.add("賈乃亮");
    Iterator<String> it = xxBrothers.iterator();
    
    it.forEachRemaining(who -> {
        System.out.println(who);
    });

---------output---------
王寶強
陳羽凡
賈乃亮
           

特别的是,不能在lamba表達式修改集合元素

Q&A

為什麼要使用疊代器,而不是使用索引方式周遊數組

Iterator設計的初衷是為了把周遊一個集合的API進行統一。無論是Array、LinkList、ArrayList或是其他集合,都可以使用疊代器進行統一周遊,而不用care集合的資料結構和實作細節。一句話:Iterator把一個集合的實作和周遊進行了分離。

Iterator接口的作用

接口是一種規範,是以Iterator接口就是規定了各個集合實作該接口時應該遵循的規範。同時,接口也隻是一種規範,至于怎麼實作這種規範,每個集合會根據自己内部的資料結構等情況考慮實作方式。如對于remove()方法的實作,ArrayList是調用其本身的remove() 方法删除最後一個位置上的元素,然後元素數量減一即可。而對于LinkList的remove()方法,則更多的是通過指針的移動來實作删除操作。

如有不适之處,歡迎留言讨論