一恳不、接口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時迭代器就越過下一個元素,并返回剛剛越過的那個元素的引用太伊。
(二)迭代器Iterator
迭代器Iterator可用于所有集合雇锡,包括Collection、Map及其子集合僚焦。(其中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鞋喇、LinkedList、Vector眉撵,其中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方法
注意: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é)倔监,若有不足或不對之處,望諸位不吝指出菌仁。