Java?迭代器Iterator完整示例解析
一、迭代器的基本概念
迭代器(Iterator)是 Java 集合框架中的一個(gè)核心接口,位于 java.util 包下。它定義了一種標(biāo)準(zhǔn)的元素訪(fǎng)問(wèn)機(jī)制,為各種集合類(lèi)型(如 List、Set、Queue 等)提供了一種統(tǒng)一的遍歷方式。
詳細(xì)說(shuō)明
- 基本功能:
hasNext():檢查集合中是否還有未遍歷的元素next():返回集合中的下一個(gè)元素remove():從集合中移除當(dāng)前元素(可選操作)
- 設(shè)計(jì)目的:
- 提供統(tǒng)一的遍歷接口,屏蔽不同集合的內(nèi)部實(shí)現(xiàn)差異
- 支持安全的并發(fā)修改(fail-fast 機(jī)制)
- 實(shí)現(xiàn)"惰性求值",只在需要時(shí)才獲取元素
- 典型使用場(chǎng)景:
List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String element = it.next();
System.out.println(element);
}
- 與其他遍歷方式的對(duì)比:
- 比傳統(tǒng)的 for 循環(huán)更安全(避免下標(biāo)越界)
- 比增強(qiáng) for 循環(huán)更靈活(支持 remove 操作)
- 適用于所有實(shí)現(xiàn) Iterable 接口的集合類(lèi)
- 注意事項(xiàng):
- 不能保證遍歷順序(具體取決于集合實(shí)現(xiàn))
- 大部分情況下不支持并發(fā)修改
- 使用后通常會(huì)成為"失效"狀態(tài)
- 擴(kuò)展機(jī)制:
- ListIterator:針對(duì) List 的增強(qiáng)迭代器,支持雙向遍歷和修改操作
- Spliterator:Java 8 引入的并行遍歷迭代器
迭代器模式是設(shè)計(jì)模式中行為型模式的一種典型實(shí)現(xiàn),體現(xiàn)了"單一職責(zé)"和"開(kāi)閉原則"的設(shè)計(jì)思想。
二、迭代器的獲取方式
在 Java 集合框架中,所有實(shí)現(xiàn)了 java.util.Collection 接口的集合類(lèi)都提供了 iterator() 方法。這個(gè)方法返回一個(gè)實(shí)現(xiàn)了 java.util.Iterator 接口的迭代器對(duì)象,用于遍歷集合中的元素。這種設(shè)計(jì)模式遵循了迭代器模式(Iterator Pattern),將集合的遍歷操作與集合的具體實(shí)現(xiàn)分離,提供了一種統(tǒng)一的方式來(lái)訪(fǎng)問(wèn)各種不同類(lèi)型的集合。
Iterator 接口定義了三個(gè)核心方法:
hasNext():判斷集合中是否還有下一個(gè)元素next():返回集合中的下一個(gè)元素remove():從集合中移除當(dāng)前元素(可選操作)
下面是一個(gè)更詳細(xì)的獲取和使用迭代器的示例代碼,展示了完整的迭代過(guò)程:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)ArrayList集合(ArrayList是Collection接口的實(shí)現(xiàn)類(lèi))
Collection<String> collection = new ArrayList<>();
// 向集合中添加元素
collection.add("張三");
collection.add("李四");
collection.add("王五");
collection.add("趙六");
// 獲取該集合的迭代器對(duì)象
Iterator<String> iterator = collection.iterator();
// 使用while循環(huán)遍歷集合元素
System.out.println("集合中的元素有:");
while(iterator.hasNext()) {
// 獲取當(dāng)前元素
String element = iterator.next();
System.out.println(element);
// 示例:移除特定元素
if(element.equals("李四")) {
iterator.remove(); // 安全地移除當(dāng)前元素
}
}
// 查看移除后的集合
System.out.println("\n移除'李四'后的集合:");
iterator = collection.iterator(); // 重新獲取迭代器
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}在實(shí)際開(kāi)發(fā)中,迭代器常用于以下場(chǎng)景:
- 需要邊遍歷邊刪除集合元素時(shí)(使用for-each循環(huán)會(huì)拋出ConcurrentModificationException)
- 需要訪(fǎng)問(wèn)某些特殊集合(如ConcurrentHashMap的視圖集合)時(shí)
- 需要統(tǒng)一處理不同類(lèi)型集合的遍歷邏輯時(shí)
需要注意的是,迭代器是單向的,一旦遍歷完成就不能重置,如果需要重新遍歷,必須重新獲取迭代器對(duì)象。此外,多個(gè)迭代器可以同時(shí)操作同一個(gè)集合,它們之間互不影響。
三、迭代器的基礎(chǔ)操作
1. hasNext() 方法
hasNext()方法用于判斷集合中是否還有下一個(gè)元素可供訪(fǎng)問(wèn),其返回值為boolean類(lèi)型。該方法不會(huì)移動(dòng)迭代器的指針位置,只是檢查當(dāng)前位置之后是否還有元素存在。
- 返回true的情況:當(dāng)集合中還有未被遍歷的元素時(shí)
- 返回false的情況:當(dāng)?shù)饕呀?jīng)到達(dá)集合末尾時(shí)
- 典型使用場(chǎng)景:作為while循環(huán)的條件,實(shí)現(xiàn)安全遍歷
// 示例:檢查集合是否為空
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
if(!it.hasNext()) {
System.out.println("集合為空");
}
2. next() 方法
next()方法用于獲取集合中的下一個(gè)元素。該方法會(huì)執(zhí)行兩個(gè)操作:
- 將迭代器的指針向后移動(dòng)一位
- 返回當(dāng)前指針?biāo)赶虻脑?/li>
注意事項(xiàng):
- 必須先用hasNext()檢查,否則當(dāng)集合中沒(méi)有更多元素時(shí)會(huì)拋出
NoSuchElementException - 每次調(diào)用都會(huì)移動(dòng)指針位置
- 返回的是Object類(lèi)型,通常需要強(qiáng)制類(lèi)型轉(zhuǎn)換
// 示例:安全使用next()
List<Integer> numbers = Arrays.asList(1, 2, 3);
Iterator<Integer> iterator = numbers.iterator();
while(iterator.hasNext()) {
Integer num = iterator.next(); // 自動(dòng)拆箱
System.out.println(num * 2); // 輸出2,4,6
}
3. remove() 方法
remove()方法用于刪除迭代器當(dāng)前所指向的元素,即上一次調(diào)用next()方法返回的元素。
方法約束:
- 必須先調(diào)用next()獲取元素后才能調(diào)用remove()
- 每次next()后只能調(diào)用一次remove()
- 不能獨(dú)立調(diào)用remove()(即不能連續(xù)調(diào)用兩次remove())
- 會(huì)直接修改底層集合的結(jié)構(gòu)
使用場(chǎng)景:
- 安全地刪除集合元素
- 在遍歷過(guò)程中動(dòng)態(tài)修改集合
// 示例:刪除特定元素
List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie"));
Iterator<String> it = names.iterator();
while(it.hasNext()) {
String name = it.next();
if(name.startsWith("A")) {
it.remove(); // 安全刪除以A開(kāi)頭的元素
}
}完整示例解析
下面是更詳細(xì)的示例代碼,展示了迭代器的完整使用流程:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class IteratorOperationDemo {
public static void main(String[] args) {
// 創(chuàng)建并初始化集合
Collection<String> collection = new ArrayList<>();
collection.add("張三");
collection.add("李四");
collection.add("王五");
collection.add("趙六");
// 獲取迭代器實(shí)例
Iterator<String> iterator = collection.iterator();
// 安全遍歷集合
try {
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println("當(dāng)前元素: " + name);
// 條件刪除
if ("李四".equals(name)) {
iterator.remove();
System.out.println("已刪除元素: 李四");
}
}
} catch (NoSuchElementException e) {
System.err.println("錯(cuò)誤: 嘗試訪(fǎng)問(wèn)不存在的元素");
} catch (IllegalStateException e) {
System.err.println("錯(cuò)誤: remove()調(diào)用不當(dāng)");
}
// 輸出修改后的集合
System.out.println("\n刪除后的集合內(nèi)容:");
iterator = collection.iterator(); // 重新獲取迭代器
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 驗(yàn)證集合大小
System.out.println("\n最終集合大小: " + collection.size());
}
}輸出結(jié)果分析:
當(dāng)前元素: 張三
當(dāng)前元素: 李四
已刪除元素: 李四
當(dāng)前元素: 王五
當(dāng)前元素: 趙六刪除后的集合內(nèi)容:
張三
王五
趙六最終集合大小: 3
最佳實(shí)踐建議
使用增強(qiáng)for循環(huán)替代簡(jiǎn)單迭代:Java 5+可以使用增強(qiáng)for循環(huán)簡(jiǎn)化遍歷
for(String name : collection) {
System.out.println(name);
}- 并發(fā)修改問(wèn)題:不要在迭代過(guò)程中直接通過(guò)集合方法修改集合結(jié)構(gòu)(如add/remove),這會(huì)導(dǎo)致
ConcurrentModificationException - 多線(xiàn)程環(huán)境:在并發(fā)環(huán)境下,應(yīng)考慮使用
ConcurrentHashMap或CopyOnWriteArrayList等線(xiàn)程安全集合 - 資源管理:對(duì)于大型集合,迭代完成后可以顯式地將迭代器置為null以幫助垃圾回收
- 性能考慮:對(duì)于ArrayList,使用索引的for循環(huán)通常比迭代器更快;但對(duì)于LinkedList,迭代器性能更好
四、迭代器的注意事項(xiàng)
在使用迭代器的過(guò)程中,有一些注意事項(xiàng)需要我們特別關(guān)注,否則可能會(huì)導(dǎo)致程序出現(xiàn)異?;虿环项A(yù)期的結(jié)果。這些注意事項(xiàng)在實(shí)際開(kāi)發(fā)中尤為重要,特別是在處理大數(shù)據(jù)集合或多線(xiàn)程環(huán)境下。
1.并發(fā)修改異常(ConcurrentModificationException)
當(dāng)我們使用迭代器遍歷集合時(shí),如果在迭代過(guò)程中通過(guò)集合本身的方法(而不是迭代器的remove()方法)修改了集合的結(jié)構(gòu)(如添加、刪除元素),則會(huì)拋出ConcurrentModificationException異常。這個(gè)異常是Java集合框架設(shè)計(jì)的fail-fast機(jī)制的體現(xiàn)。
具體來(lái)說(shuō),迭代器在創(chuàng)建時(shí)會(huì)記錄集合的modCount(修改次數(shù)),每次對(duì)集合進(jìn)行結(jié)構(gòu)性修改(如add、remove等操作)時(shí),modCount都會(huì)遞增。在迭代過(guò)程中,迭代器會(huì)檢查當(dāng)前modCount是否與創(chuàng)建時(shí)記錄的expectedModCount一致,如果不一致,就會(huì)拋出該異常。
下面是一個(gè)會(huì)拋出ConcurrentModificationException異常的典型示例代碼:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class ConcurrentModificationDemo {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
collection.add("張三");
collection.add("李四");
collection.add("王五");
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println(name);
// 通過(guò)集合的add方法添加元素,會(huì)導(dǎo)致ConcurrentModificationException異常
if ("李四".equals(name)) {
collection.add("趙六"); // 這里會(huì)拋出異常
}
}
}
}運(yùn)行上述代碼,程序會(huì)在遍歷到"李四"并嘗試添加"趙六"時(shí)拋出ConcurrentModificationException異常。這種情況常見(jiàn)于以下場(chǎng)景:
- 在foreach循環(huán)中嘗試修改集合
- 在多線(xiàn)程環(huán)境下一個(gè)線(xiàn)程迭代而另一個(gè)線(xiàn)程修改集合
為了避免出現(xiàn)這種異常,在迭代過(guò)程中如果需要修改集合的結(jié)構(gòu),應(yīng)該使用迭代器提供的remove()方法:
// 正確的修改方式 iterator.remove(); // 使用迭代器的remove方法
2.迭代器的單向性
Java中的迭代器是單向的,即只能從集合的開(kāi)頭向結(jié)尾遍歷,不能反向遍歷。這種設(shè)計(jì)主要是為了保持接口的簡(jiǎn)潔性和通用性。如果需要進(jìn)行反向遍歷,可以使用ListIterator(僅List接口的實(shí)現(xiàn)類(lèi)支持),ListIterator繼承了Iterator接口,并增加了反向遍歷的相關(guān)方法,如hasPrevious()和previous()等。
ListIterator的主要特點(diǎn)包括:
- 支持雙向遍歷
- 允許在迭代過(guò)程中修改集合
- 可以獲取當(dāng)前元素的位置
- 可以在迭代過(guò)程中添加元素
下面是一個(gè)使用ListIterator進(jìn)行反向遍歷的完整示例代碼:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("張三");
list.add("李四");
list.add("王五");
// 獲取ListIterator
ListIterator<String> listIterator = list.listIterator();
// 先正向遍歷到末尾
System.out.println("正向遍歷結(jié)果:");
while (listIterator.hasNext()) {
String name = listIterator.next();
System.out.println(name);
}
// 反向遍歷
System.out.println("\n反向遍歷結(jié)果:");
while (listIterator.hasPrevious()) {
String name = listIterator.previous();
System.out.println(name);
}
// 在迭代過(guò)程中添加元素
while (listIterator.hasNext()) {
String name = listIterator.next();
if ("李四".equals(name)) {
listIterator.add("趙六"); // 在"李四"后面添加新元素
}
}
System.out.println("\n修改后的列表:" + list);
}
}運(yùn)行上述代碼,輸出結(jié)果為:
正向遍歷結(jié)果:
張三
李四
王五反向遍歷結(jié)果:
王五
李四
張三修改后的列表:[張三, 李四, 趙六, 王五]
3.迭代器的失效
當(dāng)集合的結(jié)構(gòu)發(fā)生改變時(shí)(如使用集合的add()、remove()等方法),之前獲取的迭代器可能會(huì)失效,繼續(xù)使用該迭代器可能會(huì)出現(xiàn)不可預(yù)期的結(jié)果或拋出異常。這種情況在以下場(chǎng)景中特別常見(jiàn):
- 在多線(xiàn)程環(huán)境中共享集合
- 在長(zhǎng)時(shí)間運(yùn)行的迭代過(guò)程中
- 在嵌套迭代時(shí)
因此,當(dāng)集合的結(jié)構(gòu)發(fā)生改變后,最佳實(shí)踐是重新獲取迭代器。例如:
List<String> list = new ArrayList<>();
// ...添加元素...
Iterator<String> iter1 = list.iterator();
// 修改集合結(jié)構(gòu)
list.add("新元素");
// 舊的迭代器可能失效,應(yīng)該重新獲取
Iterator<String> iter2 = list.iterator(); // 獲取新的迭代器4.對(duì)于不同集合的迭代器實(shí)現(xiàn)
不同的集合類(lèi)對(duì)迭代器接口的實(shí)現(xiàn)可能有所不同,因此在使用迭代器遍歷不同的集合時(shí),其性能和行為可能會(huì)存在顯著差異。
以下是一些常見(jiàn)集合類(lèi)的迭代器特點(diǎn)比較:
| 集合類(lèi)型 | 迭代器特點(diǎn) | 適用場(chǎng)景 |
|---|---|---|
| ArrayList | 基于數(shù)組實(shí)現(xiàn),next()方法效率高(O(1)),但插入刪除操作會(huì)導(dǎo)致數(shù)組復(fù)制 | 隨機(jī)訪(fǎng)問(wèn)頻繁,修改操作少 |
| LinkedList | 基于鏈表實(shí)現(xiàn),next()需要移動(dòng)指針(O(n)),但插入刪除效率高(O(1)) | 頻繁插入刪除操作 |
| HashSet | 基于哈希表實(shí)現(xiàn),迭代順序不確定 | 快速查找,不關(guān)心順序 |
| TreeSet | 基于紅黑樹(shù)實(shí)現(xiàn),迭代順序是有序的 | 需要有序遍歷 |
| ConcurrentHashMap | 弱一致性的迭代器,線(xiàn)程安全 | 多線(xiàn)程環(huán)境 |
選擇集合類(lèi)型時(shí)的建議:
- 如果需要頻繁隨機(jī)訪(fǎng)問(wèn),選擇ArrayList
- 如果需要頻繁插入刪除,選擇LinkedList
- 多線(xiàn)程環(huán)境下考慮并發(fā)集合類(lèi)
- 大數(shù)據(jù)量時(shí)考慮迭代器的性能差異
例如,在遍歷LinkedList時(shí),使用普通for循環(huán)的性能會(huì)很差:
// 性能差的方式(LinkedList)
for (int i = 0; i < linkedList.size(); i++) {
String s = linkedList.get(i); // 每次get(i)都需要從頭遍歷
}
// 推薦的方式(使用迭代器)
Iterator<String> iter = linkedList.iterator();
while (iter.hasNext()) {
String s = iter.next(); // 只需移動(dòng)指針
}理解這些差異有助于我們?cè)趯?shí)際開(kāi)發(fā)中選擇合適的集合類(lèi)型和遍歷方式,從而提高程序性能。
到此這篇關(guān)于Java 迭代器Iterator完整示例解析的文章就介紹到這了,更多相關(guān)Java 迭代器Iterator內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java日期格式化SimpleDateFormat的使用詳解
這篇文章主要介紹了java SimpleDateFormat使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
Spring?Boot與Redis的緩存一致性問(wèn)題解決
在使用緩存時(shí),緩存一致性問(wèn)題是一個(gè)常見(jiàn)的挑戰(zhàn),本文主要介紹了Spring?Boot與Redis的緩存一致性問(wèn)題,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07
使用springboot對(duì)外部靜態(tài)資源文件的處理操作
這篇文章主要介紹了使用springboot對(duì)外部靜態(tài)資源文件的處理操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
剖析Spring WebFlux反應(yīng)式編程設(shè)計(jì)及工作原理
這篇文章主要為大家介紹了Spring WebFlux反應(yīng)式編程模型工作原理的剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-02-02
Spring中IoC優(yōu)點(diǎn)與缺點(diǎn)解析
這篇文章主要為大家詳細(xì)解析了Spring中IoC優(yōu)點(diǎn)與缺點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11

