溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用迭代器

發(fā)布時(shí)間:2021-10-19 15:49:32 來(lái)源:億速云 閱讀:111 作者:iii 欄目:web開(kāi)發(fā)

本篇內(nèi)容介紹了“如何使用迭代器”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

閱讀下面這段代碼,請(qǐng)寫(xiě)出這段代碼的輸出內(nèi)容:

import java.util.ArrayList; import java.util.Iterator; import java.util.*;  public class Test {     public static void main(String[] args) {          List<String> list = new ArrayList<>();         list.add("1");         list.add("2");         list.add("3");         Iterator iterator = list.iterator();         while (iterator.hasNext()) {             String str = (String) iterator.next();             if (str.equals("2")) {                 iterator.remove();             }         }         while (iterator.hasNext()) {             System.out.println(iterator.next());         }         System.out.println("4");     } }

他寫(xiě)出來(lái)的答案是:

1 3 4

奇怪的是,你把這道題目發(fā)給你身邊人,讓他們回答這道面試題輸出結(jié)果是什么,說(shuō)這個(gè)結(jié)果的人非常多。不行你試試。

答案明顯不對(duì),因?yàn)樵诘谝粋€(gè)while里的  iterator.hasNext()==false后才會(huì)到第二個(gè)while里來(lái),同一個(gè)Iterator對(duì)象,前面調(diào)一次iterator.hasNext()==false,再判斷一次結(jié)果不還是一樣嗎?,

所以第二個(gè)while判斷為false,也就不會(huì)再去遍歷iterator了,由此可知本體答案是:4。

下面我們來(lái)分析一下為什么是具體底層是怎么實(shí)現(xiàn)的。

這里的Iterator是什么?

  • 迭代器是一種模式、詳細(xì)可見(jiàn)其設(shè)計(jì)模式,可以使得序列類型的數(shù)據(jù)結(jié)構(gòu)的遍歷行為與被遍歷的對(duì)象分離,即我們無(wú)需關(guān)心該序列的底層結(jié)構(gòu)是什么樣子的。只要拿到這個(gè)對(duì)象,使用迭代器就可以遍歷這個(gè)對(duì)象的內(nèi)部

  • Iterable 實(shí)現(xiàn)這個(gè)接口的集合對(duì)象支持迭代,是可以迭代的。實(shí)現(xiàn)了這個(gè)可以配合foreach使用~

  • Iterator 迭代器,提供迭代機(jī)制的對(duì)象,具體如何迭代是這個(gè)Iterator接口規(guī)范的。

Iterator說(shuō)明

public interface Iterator<E> {      //每次next之前,先調(diào)用此方法探測(cè)是否迭代到終點(diǎn)     boolean hasNext();     //返回當(dāng)前迭代元素 ,同時(shí),迭代游標(biāo)后移     E next();      /*刪除最近一次已近迭代出出去的那個(gè)元素。      只有當(dāng)next執(zhí)行完后,才能調(diào)用remove函數(shù)。      比如你要?jiǎng)h除第一個(gè)元素,不能直接調(diào)用 remove()   而要先next一下( );      在沒(méi)有先調(diào)用next 就調(diào)用remove方法是會(huì)拋出異常的。      這個(gè)和MySQL中的ResultSet很類似     */     default void remove() {         throw new UnsupportedOperationException("remove");     }      default void forEachRemaining(Consumer<? super E> action) {         Objects.requireNonNull(action);         while (hasNext())             action.accept(next());     } }

這里的實(shí)現(xiàn)類是ArrayList的內(nèi)部類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         //modCountshi ArrayList中的屬性,當(dāng)添加或刪除的時(shí)候moCount值會(huì)增加或者減少         //這里主要是給fail-fast使用,避免一遍在遍歷,一遍正在修改導(dǎo)致數(shù)據(jù)出錯(cuò)         //此列表在結(jié)構(gòu)上被修改的次數(shù)。結(jié)構(gòu)修改是指改變結(jié)構(gòu)尺寸的修改列表,         //或者以這樣的方式對(duì)其進(jìn)行擾動(dòng),進(jìn)步可能會(huì)產(chǎn)生錯(cuò)誤的結(jié)果。         int expectedModCount = modCount;                  public boolean hasNext() {             //cursor初始值為0,沒(méi)掉一次next方法就+1             //size是ArrayList的大小             return cursor != size;         }          @SuppressWarnings("unchecked")         public E next() {             checkForComodification();             int i = cursor;             if (i >= size)                 throw new NoSuchElementException();             //把ArrayList中的數(shù)組賦給elementData             Object[] elementData = ArrayList.this.elementData;             if (i >= elementData.length)                 throw new ConcurrentModificationException();             //每調(diào)用一次next方法,游標(biāo)就加1             //cursor=lastRet+1             cursor = i + 1;             //返回ArrayList中的元素             return (E) elementData[lastRet = i];         }          public void remove() {             if (lastRet < 0)                 throw new IllegalStateException();             checkForComodification();              try {                 //調(diào)用ArrayList中remove方法,溢出該元素                 ArrayList.this.remove(lastRet);                 //cursor=lastRet+1,                 //所以此時(shí)相當(dāng)于cursor=cursor-1                 cursor = lastRet;                 lastRet = -1;                 expectedModCount = modCount;             } catch (IndexOutOfBoundsException ex) {                 throw new ConcurrentModificationException();             }         }         final void checkForComodification() {             if (modCount != expectedModCount)                 throw new ConcurrentModificationException();         } }

再回到上面題目中:

第一個(gè)iterator.hasNext()

  • 第1次循環(huán)hasNext方法中:cursor==0, size==3,所以cursor !=  size返回true。

  • next方法中:cursor=0+1。返回"1"。

第2次循環(huán)

  • hasNext方法中:cursor==1, size==3,所以cursor != size返回true。

  • next方法中:cursor=1+1。返回"2"。

  • remove方法中:cursor==cursor-1==2-1=1,把ArrayList中的"2"給刪除了,所以size==2。

第3次循環(huán)

  • hasNext方法中:cursor==1, size==2,那么cursor != size返回true。

  • next方法中:cursor=1+1==2;返回"3"。

第4次循環(huán)

  • hasNext方法中:cursor==2, size==2,那么cursor != size返回false。

第二個(gè)iterator.hasNext()

hasNext方法中:cursor==2, size==2,所以cursor !=  size返回false。

所以,最后只輸出"4",即答案為4.

Iterator與泛型搭配

  • Iterator對(duì)集合類中的任何一個(gè)實(shí)現(xiàn)類,都可以返回這樣一個(gè)Iterator對(duì)象??梢赃m用于任何一個(gè)類。

  • 因?yàn)榧项?List和Set等)可以裝入的對(duì)象的類型是不確定的,從集合中取出時(shí)都是Object類型,用時(shí)都需要進(jìn)行強(qiáng)制轉(zhuǎn)化,這樣會(huì)很麻煩,用上泛型,就是提前告訴集合確定要裝入集合的類型,這樣就可以直接使用而不用顯示類型轉(zhuǎn)換.非常方便.

foreach和Iterator的關(guān)系

  • for  each以用來(lái)處理集合中的每個(gè)元素而不用考慮集合定下標(biāo)。就是為了讓用Iterator簡(jiǎn)單。但是刪除的時(shí)候,區(qū)別就是在remove,循環(huán)中調(diào)用集合remove會(huì)導(dǎo)致原集合變化導(dǎo)致錯(cuò)誤,而應(yīng)該用迭代器的remove方法。

使用for循環(huán)還是迭代器Iterator對(duì)比

  • 采用ArrayList對(duì)隨機(jī)訪問(wèn)比較快,而for循環(huán)中的get()方法,采用的即是隨機(jī)訪問(wèn)的方法,因此在ArrayList里,for循環(huán)較快

  • 采用LinkedList則是順序訪問(wèn)比較快,iterator中的next()方法,采用的即是順序訪問(wèn)的方法,因此在LinkedList里,使用iterator較快

  • 從數(shù)據(jù)結(jié)構(gòu)角度分析,for循環(huán)適合訪問(wèn)順序結(jié)構(gòu),可以根據(jù)下標(biāo)快速獲取指定元素.而Iterator  適合訪問(wèn)鏈?zhǔn)浇Y(jié)構(gòu),因?yàn)榈魇峭ㄟ^(guò)next()和Pre()來(lái)定位的.可以訪問(wèn)沒(méi)有順序的集合.

  • 而使用 Iterator 的好處在于可以使用相同方式去遍歷集合中元素,而不用考慮集合類的內(nèi)部實(shí)現(xiàn)(只要它實(shí)現(xiàn)了 java.lang.Iterable  接口),如果使用 Iterator 來(lái)遍歷集合中元素,一旦不再使用 List 轉(zhuǎn)而使用 Set 來(lái)組織數(shù)據(jù),那遍歷元素的代碼不用做任何修改,如果使用 for  來(lái)遍歷,那所有遍歷此集合的算法都得做相應(yīng)調(diào)整,因?yàn)長(zhǎng)ist有序,Set無(wú)序,結(jié)構(gòu)不同,他們的訪問(wèn)算法也不一樣.(還是說(shuō)明了一點(diǎn)遍歷和集合本身分離了)。

總結(jié)

  • 迭代出來(lái)的元素都是原來(lái)集合元素的拷貝。

  • Java集合中保存的元素實(shí)質(zhì)是對(duì)象的引用,而非對(duì)象本身。

  • 迭代出的對(duì)象也是引用的拷貝,結(jié)果還是引用。那么如果集合中保存的元素是可變類型的,那么可以通過(guò)迭代出的元素修改原集合中的對(duì)象。

“如何使用迭代器”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI