關(guān)于Java集合中的迭代

一恳不、接口Iterable和接口Iterator的區(qū)分及聯(lián)系

【英文釋義】
Iterable:可迭代的交惯,形容詞浅妆。
Iterator:迭代器,名詞壳嚎。

Iterable JDK源碼:

public interface Iterable<T>
{
    Iterator<T> iterator();//iterator方法用于返回一個實現(xiàn)了Iterator接口的對象
}

Iterator JDK源碼:

public interface Iterator<E> {
    boolean hasNext(); //每次next之前桐智,先調(diào)用此方法探測是否迭代到終點
    E next();            //返回當(dāng)前迭代元素 末早,同時,迭代游標(biāo)后移
    void remove() ;
}

以下是筆者對于兩者區(qū)分及聯(lián)系的理解:
(1) 迭代器iterator是用來遍歷集合中元素的工具酵使。任何一個集合要想通過迭代的方式遍歷元素則必須獲得一個屬于自身的迭代器荐吉;
(2) 接口Iterable中提供了一種方法為iterator(),該方法用于返回一個實現(xiàn)了Iterator接口的對象口渔,即返回一個迭代器样屠;
(3) 集合的基本接口Collection繼承了接口Iterable,故所有直接或間接實現(xiàn)了接口Collection的集合類都是可迭代的缺脉,都可以通過調(diào)用.iterator()方法得到一個屬于自身的迭代器痪欲。


二、迭代器Iterator及列表迭代器ListIterator

(一)Java迭代器

java迭代器中查找一個元素的唯一方法時調(diào)用next攻礼,在執(zhí)行查找操作的同時业踢,迭代器位置隨之向前移動。因此礁扮,應(yīng)該將java迭代器認(rèn)為是位于兩個元素之間知举,當(dāng)調(diào)用next時迭代器就越過下一個元素,并返回剛剛越過的那個元素的引用太伊。

向前移動的Java迭代器

(二)迭代器Iterator

迭代器Iterator可用于所有集合雇锡,包括CollectionMap及其子集合僚焦。(其中Map使用迭代器是通過映射的方式得到一個set集合锰提,然后再迭代,具體方式可以見Map的遍歷方法芳悲,這里不再贅述)立肘。
Iterator接口包含4個方法:

public interface Iterator<E>
{
  E next();
  boolean hasNext();
  default void remove();
  default void forEachRemaining(Consumer<? super E> action);
}

—hashNext()方法
如果迭代器對象還有多個供訪問的元素,則返回true名扛,否則返回false谅年。
—next()方法
反復(fù)調(diào)用next()方法可以逐個訪問集合中的元素,但是到達(dá)了集合的末尾肮韧,next方法會拋出一個NoSuchElementException踢故。故在調(diào)用next方法之前要調(diào)用hasNext方法。
特別注意的是惹苗,next方法返回的是一個集合元素。
—remove()方法
remove()方法將會刪除的是上次調(diào)用next方法時返回的元素耸峭。并且next方法和remove方法具有互相依賴性桩蓉。如果調(diào)用remove之前沒有調(diào)用next方法將會是不合法的,會拋出IllegalStateException異常劳闹。例如:

Collection<String> c = .......;
Iterator it = c.iterator();
//連續(xù)刪除兩個元素這么做是不合法的:
it.next();
it.remove();
it.remove();//error
//應(yīng)該這么做:
it.next();
it.remove();
it.next();
it.remove();

—forEachRemaining()方法
在Java SE 8中院究,可以調(diào)用forEachRemaining方法并提供一個lambda表達(dá)式(它會處理一個元素)洽瞬。將對迭代器的每一個元素調(diào)用這個lambda表達(dá)式,直到再沒有元素為止业汰。

iterator.forEachRemaining(element-> do something with element);

(三)列表迭代器ListIterator

迭代器ListIterator繼承于Iterator伙窃,只能用于List及其子集合。
首先來看看接口ListIterator的JDK源碼:

public interface ListIterator<E> extends Iterator<E> {
  boolean hasNext();
  E next();
  void remove();
  boolean hasPrevious();
  E previous();
  int nextIndex();//返回下一次調(diào)用next方法時將返回的元素索引
  int previousIndex();//返回下一次調(diào)用previous方法時將返回的元素索引
  void set(E e);//用新元素取代next或previous上次訪問的元素样漆,如果在next或previous上次調(diào)用之后列表結(jié)構(gòu)被修改了將拋出IllegalStateException異常
  void add(E e);//在當(dāng)前位置前添加一個元素为障,注意與Collection的add方法不同
}

補充:
List與泛型集合之間有一個重要的區(qū)別是,List是一個有序集合放祟,每個對象的位置都很重要鳍怨,且List是有序可重復(fù)的。
List接口有三個實現(xiàn)集合類跪妥,分別是ArrayList鞋喇、LinkedListVector眉撵,其中ArrayList底層采用數(shù)組存儲元素侦香,LinkedList底層采用雙向鏈表存儲元素,Vector底層與ArrayList相同(但是它是線程安全的纽疟、效率低)
List接口定義了多個用于隨機訪問的方法罐韩,以下是List接口的部分JDK源碼:

public interface List<E> extends Collection<E> {
  int size();
  boolean add(E e);
  boolean remove(Object o);
  E get(int index);
  E set(int index, E element);
  void add(int index, E element);
  E remove(int index);
  int indexOf(Object o);
}

—void add(E e)方法
特別注意的是,接口ListIterator的add()方法返回值類型是void仰挣,而Collection接口中的add()方法返回值類型是boolean伴逸。
因此,List.add方法是將對象添加到鏈表的尾部膘壶,如果有時候想要在列表的中間插入元素則顯得有點棘手(比如基于數(shù)組實現(xiàn)的列表)错蝴。由于迭代器是描述集合中位置的,所以這種依賴于位置的add()方法將由迭代器負(fù)責(zé)颓芭。

List<String> staff = new LinkedList<>();
staff.add("張三");//Collection中的add方法
staff.add("李四");
staff.add("王五");
ListIterator<String> lt = staff.listIterator();
lt.next();
lt.add("趙六");//ListIterator中的add方法

代碼執(zhí)行示意圖

注意:List接口中也有一個add方法顷锰,void add(int index, E element),該方法用在此列表的指定位置插入指定的元素(可選操作)亡问。將當(dāng)前在該位置的元素(如果有)和任何后續(xù)元素向右移官紫。前提是知道索引值。
補充:add方法只依賴于迭代器位置州藕,而remove方法依賴于迭代器的狀態(tài)束世。
—void set(E e)方法
再來說明一個比較不一樣的方法,set方法用一個新元素取代調(diào)用next或者previous方法返回的上一個元素床玻,下面代碼將用一個新值取代鏈表的第一個元素:

List<E> list = new LinkedList<E>();
ListIterator<E> lt = list.listIterator();
E oldValue = lt.next();
lt.set(newValue);

注意:List接口中也有一個set方法毁涉,E set(int index, E element),該方法用指定的元素替換此列表中指定位置處的元素锈死,前提是知道索引值贫堰。
—int nextIndex()穆壕、int previousIndex()方法
列表迭代器接口還可以通過int nextIndex()、int previousIndex()方法方法告知當(dāng)前位置的索引其屏。實際上喇勋,從概念上說,由于Java迭代器指向兩個元素之間的位置偎行,所以可以同時產(chǎn)生兩個索引:
nextIndex() 返回下一次調(diào)用next方法時將返回的元素索引;
previousIndex() 返回下一次調(diào)用previous方法時將返回的元素索引川背。

(四)多迭代器

如果在某個迭代器修改集合時,另一個迭代器對其進(jìn)行遍歷睦优,一定會出現(xiàn)混亂的狀況渗常。為了避免并發(fā)情況下修改的異常,應(yīng)遵循以下規(guī)則:
可以根據(jù)需要給容器附加許多的迭代器汗盘,但是這些迭代器只能讀取列表皱碘。另外,再單獨附加一個既能讀又能寫的迭代器隐孽。


三癌椿、總結(jié)

迭代器Iterator及列表迭代器ListIterator的區(qū)別:
(1)Iterator可以用于所有集合,Set菱阵、List踢俄、Map等等及其子集合,ListIterator只能用于List及其子集合晴及;
(2)ListIterator有add都办、set方法,能添加虑稼、替換對象琳钉;
(3)ListIterator有hasPrevious和previous方法,可以逆向遍歷蛛倦;
(4)ListIterator可以定位當(dāng)前索引位置歌懒,nextIndex和previousIndex可以實現(xiàn);

補充
Java集合中保存的元素實質(zhì)是對象的引用溯壶,迭代出來的元素都是原來集合元素的拷貝及皂,也就是說迭代出的元素都是引用的拷貝,結(jié)果還是引用且改。
那么验烧,如果集合中保存的元素是可變類型的,我們就可以通過迭代出的元素修改原集合中的對象又跛。而對于不可變類型噪窘,如String 基本元素的包裝類型Integer 都是則不會反應(yīng)到原集合中。可見https://www.cnblogs.com/keyi/p/5821285.html


以上便是筆者的一些總結(jié)倔监,若有不足或不對之處,望諸位不吝指出菌仁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浩习,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子济丘,更是在濱河造成了極大的恐慌谱秽,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摹迷,死亡現(xiàn)場離奇詭異疟赊,居然都是意外死亡,警方通過查閱死者的電腦和手機峡碉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門近哟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鲫寄,你說我怎么就攤上這事吉执。” “怎么了地来?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵戳玫,是天一觀的道長。 經(jīng)常有香客問我未斑,道長咕宿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任蜡秽,我火速辦了婚禮府阀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘载城。我一直安慰自己肌似,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布诉瓦。 她就那樣靜靜地躺著川队,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睬澡。 梳的紋絲不亂的頭發(fā)上固额,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音煞聪,去河邊找鬼斗躏。 笑死,一個胖子當(dāng)著我的面吹牛昔脯,可吹牛的內(nèi)容都是我干的啄糙。 我是一名探鬼主播笛臣,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隧饼!你這毒婦竟也來了沈堡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤燕雁,失蹤者是張志新(化名)和其女友劉穎诞丽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拐格,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡僧免,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捏浊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懂衩。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呛伴,靈堂內(nèi)的尸體忽然破棺而出勃痴,到底是詐尸還是另有隱情,我是刑警寧澤热康,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布沛申,位于F島的核電站,受9級特大地震影響姐军,放射性物質(zhì)發(fā)生泄漏铁材。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一奕锌、第九天 我趴在偏房一處隱蔽的房頂上張望著觉。 院中可真熱鬧,春花似錦惊暴、人聲如沸饼丘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肄鸽。三九已至,卻和暖如春油啤,著一層夾襖步出監(jiān)牢的瞬間典徘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工益咬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逮诲,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像梅鹦,于是被迫代替她去往敵國和親裆甩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355