字節(jié)面試官問:Iterator和erable有什么區(qū)別?

1.前言
在面試的時候摆昧,如果面試官問你:Iterator 和 Iterable 有什么區(qū)別撩满,你會怎么回答這個問題呢蜒程?要是一年前的我來回答這個問題的話绅你,估計我直接就如鯁在喉、啞口無言了昭躺,不過現(xiàn)在的我還是能跟面試官聊上幾句的忌锯,那么今天就和各位小伙伴分享一下我對 Iterator 和 Iterable 的理解。

2.Iterator 和 Iterable
定義
在聊 Iterator 和 Iterable 之前领炫,我們得先明白二者的定義偶垮,俗話說“繁瑣問題必有猥瑣解法”,我們用一個“猥瑣”的方式來理解二者的含義

Iterable:英語好的小伙伴應(yīng)該都知道帝洪,以 able 結(jié)尾的單詞似舵,表示的含義都是【可以…】或【支持…】,那么 Iterable 所代表的含義也就是可迭代的葱峡、支持迭代的砚哗,因此我們可以知道,實現(xiàn)了 Iterable 接口的對象是支持迭代砰奕,是可迭代的蛛芥。

Iterator:在英語中以 or 結(jié)尾的單詞表示的含義是【 …樣的人】或【 …者】,就像 creator 表示的是創(chuàng)作者的意思军援。那么這里也是一樣的仅淑,iterator 就是迭代者,我們一般叫迭代器胸哥,它就是提供迭代機制的對象涯竟,具體如何迭代,都是 Iterator 接口來規(guī)范的。

P.S. 在 Java 設(shè)計模式中也有一種模式叫迭代器模式昆禽,Iterator 就是迭代器模式的一個應(yīng)用例子

Iterable源碼及方法
Iterable 源碼

public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();

/**
 * Performs the given action for each element of the {@code Iterable}
 * until all elements have been processed or the action throws an
 * exception.  Unless otherwise specified by the implementing class,
 * actions are performed in the order of iteration (if an iteration order
 * is specified).  Exceptions thrown by the action are relayed to the
 * caller.
 *
 * @implSpec
 * <p>The default implementation behaves as if:
 * <pre>{@code
 *     for (T t : this)
 *         action.accept(t);
 * }</pre>
 *
 * @param action The action to be performed for each element
 * @throws NullPointerException if the specified action is null
 * @since 1.8
 */
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}


/**
 * Creates a {@link Spliterator} over the elements described by this
 * {@code Iterable}.
 *
 * @implSpec
 * The default implementation creates an
 * <em><a href="Spliterator.html#binding">early-binding</a></em>
 * spliterator from the iterable's {@code Iterator}.  The spliterator
 * inherits the <em>fail-fast</em> properties of the iterable's iterator.
 *
 * @implNote
 * The default implementation should usually be overridden.  The
 * spliterator returned by the default implementation has poor splitting
 * capabilities, is unsized, and does not report any spliterator
 * characteristics. Implementing classes can nearly always provide a
 * better implementation.
 *
 * @return a {@code Spliterator} over the elements described by this
 * {@code Iterable}.
 * @since 1.8
 */
default Spliterator<T> spliterator() {
    return Spliterators.spliteratorUnknownSize(iterator(), 0);
}

}
通過源碼我們可以到 Iterable 接口中有三個方法蝗蛙,分別是:

Iterator iterator() :該接口主要是用來返回T類型的元素上的一個迭代器。

default void forEach(Consumer action) :該方法是循環(huán)輸出醉鳖,對內(nèi)部元素進行遍歷并對元素進行指定的操作捡硅。

default Spliterator spliterator():該方法提供了一個可以并行遍歷元素的迭代器,以適應(yīng)現(xiàn)在cpu多核時代并行遍歷的需求盗棵。

Iterator 源碼及方法
Iterator源碼

public interface Iterator<E> {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();

/**
 * Returns the next element in the iteration.
 *
 * @return the next element in the iteration
 * @throws NoSuchElementException if the iteration has no more elements
 */
E next();


/**
 * Removes from the underlying collection the last element returned
 * by this iterator (optional operation).  This method can be called
 * only once per call to {@link #next}.  The behavior of an iterator
 * is unspecified if the underlying collection is modified while the
 * iteration is in progress in any way other than by calling this
 * method.
 *
 * @implSpec
 * The default implementation throws an instance of
 * {@link UnsupportedOperationException} and performs no other action.
 *
 * @throws UnsupportedOperationException if the {@code remove}
 *         operation is not supported by this iterator
 *
 * @throws IllegalStateException if the {@code next} method has not
 *         yet been called, or the {@code remove} method has already
 *         been called after the last call to the {@code next}
 *         method
 */
default void remove() {
    throw new UnsupportedOperationException("remove");
}


/**
 * Performs the given action for each remaining element until all elements
 * have been processed or the action throws an exception.  Actions are
 * performed in the order of iteration, if that order is specified.
 * Exceptions thrown by the action are relayed to the caller.
 *
 * @implSpec
 * <p>The default implementation behaves as if:
 * <pre>{@code
 *     while (hasNext())
 *         action.accept(next());
 * }</pre>
 *
 * @param action The action to be performed for each element
 * @throws NullPointerException if the specified action is null
 * @since 1.8
 */
default void forEachRemaining(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    while (hasNext())
        action.accept(next());
}

}
通過源碼我們可以看到壮韭,Iterator 中包含了四個方法,分別是:

boolean hasNext():判斷需要遍歷的集合是否存在下一個元素纹因,即如果被迭代遍歷的集合還沒有被遍歷完喷屋,返回 true

E next():返回集合里面的下一個元素

default void remove():刪除集合里面上一次 next() 方法返回的元素

forEachRemaining(Consumer action):該方法是JDK 1.8后新增默認方法,含義是使用Lambda表達式來遍歷集合元素

看到這可能有些小伙伴就會問了:default void forEachRemaining(Consumer action) 方法怎么用呢瞭恰?它和 forEach() 方法又有什么區(qū)別呢屯曹?我們接著往下看~

forEachRemaining 方法是使用就很簡單了,直接給大家貼一個示例代碼

public static void main(String[] args) {
List list = new ArrayList<String>();
list.add("我在");
list.add("人民廣場");
list.add("吃著炸雞");
list.iterator().forEachRemaining(str-> System.out.println(str));
}
關(guān)于二者的區(qū)別也很簡單惊畏,我們通過源碼就可以一目了然~

forEachRemaining()源碼

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

default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
這兩個方法說是跟孫悟空和六耳獼猴一樣恶耽,二者長得太像了,他們都可以遍歷集合而且都是接口的默認方法颜启,唯一不同的地方就是循環(huán)方式不一樣偷俭。前者內(nèi)部是通過使用迭代器來遍歷的所有元素;而后者內(nèi)部使用的是增強 for 循環(huán)遍歷的元素缰盏,不同的遍歷方式也導(dǎo)致了 forEach() 方法可以多次調(diào)用涌萤,而 forEachRemaining() 方法在第二次調(diào)用時不會做任何操作,因為不會有下一個元素了口猜。

Iterator 和 Iterable 的區(qū)別

通過上面的講解负溪,相信各位小伙伴對 Iterator 和 Iterable 有了一些自己的見解,最后我們再一起總結(jié)一下二者之間的區(qū)別济炎。

Iterator 是迭代器類川抡,而 Iterable 是一個接口,約束某類是否可迭代冻辩,某個類只要實現(xiàn)了 Iterable 接口就可以使用 foreach 進行迭代猖腕。同時 Iterable 中又封裝了 Iterator 接口迅耘,只要實現(xiàn)了 Iterable 接口的類混驰,也就可以使用 Iterator 迭代器了年扩。集合Collection蚤认、List贱呐、Set都是 Iterable 的實現(xiàn)類关面,所以他們及其他們的子類都可以使用 foreach 進行迭代蜕青。

上面我們提到了 Collection瘟栖、List、Set 都是 Iterable 的實現(xiàn)類蜡豹,那為什么一定要去實現(xiàn) Iterable 這個接口呢麸粮?直接實現(xiàn) Iterator 接口不行嗎?答案肯定是不行的镜廉,原因也很簡單

Iterator 接口中的核心方法 next() 或 hasNext() 是依賴于迭代器的當前迭代位置的弄诲。如果Collection直接實現(xiàn)Iterator接口,則導(dǎo)致集合對象中包含當前迭代位置的數(shù)據(jù)(可以理解成指針)娇唯。當集合在不同方法間被傳遞時齐遵,由于當前迭代位置不可預(yù)知,那么 next() 方法的結(jié)果也就成了一個未知數(shù)塔插;而 Iterable 則不然梗摇,每次調(diào)用都會返回一個從頭開始計數(shù)的迭代器,并且多個迭代器是互不干擾的想许,所以 Collection伶授、List、Set 集合實現(xiàn)的是 Iterable 而非 Iterator 流纹。

總結(jié)
經(jīng)驗有限糜烹,有些地方可能講的沒有特別到位,如果文章中有錯誤捧颅,歡迎大家留言指正景图;若您有更好较雕、更獨到的理解碉哑,歡迎您留下寶貴想法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末亮蒋,一起剝皮案震驚了整個濱河市扣典,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慎玖,老刑警劉巖贮尖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趁怔,居然都是意外死亡湿硝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門润努,熙熙樓的掌柜王于貴愁眉苦臉地迎上來关斜,“玉大人,你說我怎么就攤上這事铺浇×⌒螅” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長丁稀。 經(jīng)常有香客問我吼拥,道長,這世上最難降的妖魔是什么线衫? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任凿可,我火速辦了婚禮,結(jié)果婚禮上授账,老公的妹妹穿的比我還像新娘矿酵。我一直安慰自己,他們只是感情好矗积,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布全肮。 她就那樣靜靜地躺著,像睡著了一般棘捣。 火紅的嫁衣襯著肌膚如雪辜腺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天乍恐,我揣著相機與錄音评疗,去河邊找鬼。 笑死茵烈,一個胖子當著我的面吹牛百匆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播呜投,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼加匈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了仑荐?” 一聲冷哼從身側(cè)響起雕拼,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粘招,沒想到半個月后啥寇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡洒扎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年辑甜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袍冷。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡磷醋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出难裆,到底是詐尸還是另有隱情子檀,我是刑警寧澤镊掖,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站褂痰,受9級特大地震影響亩进,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缩歪,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一归薛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匪蝙,春花似錦主籍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颤绕,卻和暖如春幸海,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奥务。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工物独, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氯葬。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓挡篓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帚称。 傳聞我的和親對象是個殘疾皇子官研,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容