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

