Java Iterator
Iterator 是用來遍歷集合的介面,提供統一的遍歷方式。
基本使用
List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String element = it.next();
System.out.println(element);
}
Iterator 方法
| 方法 | 說明 |
|---|---|
hasNext() | 是否有下一個元素 |
next() | 取得下一個元素 |
remove() | 移除當前元素 |
forEachRemaining() | 對剩餘元素執行操作 |
安全地刪除元素
使用 Iterator 可以在遍歷時安全地刪除元素:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
// 錯誤:會拋出 ConcurrentModificationException
// for (String s : list) {
// if (s.equals("B")) {
// list.remove(s);
// }
// }
// 正確:使用 Iterator
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("B")) {
it.remove(); // 安全刪除
}
}
// [A, C, D]
forEachRemaining()
Java 8+ 可以對剩餘元素執行操作:
List<String> list = Arrays.asList("A", "B", "C", "D");
Iterator<String> it = list.iterator();
it.next(); // 跳過 "A"
it.forEachRemaining(System.out::println);
// B, C, D
ListIterator
ListIterator 是 List 專用的迭代器,支援雙向遍歷:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
ListIterator<String> it = list.listIterator();
// 正向遍歷
while (it.hasNext()) {
System.out.println(it.next());
}
// 反向遍歷
while (it.hasPrevious()) {
System.out.println(it.previous());
}
ListIterator 方法
| 方法 | 說明 |
|---|---|
hasPrevious() | 是否有前一個元素 |
previous() | 取得前一個元素 |
nextIndex() | 下一個元素的索引 |
previousIndex() | 前一個元素的索引 |
add() | 新增元素 |
set() | 修改當前元素 |
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("B")) {
it.set("X"); // 修改為 "X"
it.add("Y"); // 在後面插入 "Y"
}
}
// [A, X, Y, C]
不同集合的 Iterator
// List
List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> listIt = list.iterator();
// Set
Set<String> set = new HashSet<>(Arrays.asList("A", "B", "C"));
Iterator<String> setIt = set.iterator();
// Map (遍歷 entry)
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
Iterator<Map.Entry<String, Integer>> mapIt = map.entrySet().iterator();
while (mapIt.hasNext()) {
Map.Entry<String, Integer> entry = mapIt.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Iterator vs for-each
List<String> list = Arrays.asList("A", "B", "C");
// for-each(語法糖,內部使用 Iterator)
for (String s : list) {
System.out.println(s);
}
// Iterator
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
使用 Iterator 的情況:
- 需要刪除元素
- 需要取得索引
- 需要反向遍歷
自訂 Iterable
讓自訂類別支援 for-each:
public class Range implements Iterable<Integer> {
private int start;
private int end;
public Range(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int current = start;
@Override
public boolean hasNext() {
return current < end;
}
@Override
public Integer next() {
return current++;
}
};
}
}
// 使用
for (int i : new Range(0, 5)) {
System.out.println(i);
}
// 0, 1, 2, 3, 4
注意事項
ConcurrentModificationException
在遍歷時直接修改集合會拋出例外:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
// 這樣會出錯
for (String s : list) {
list.add("D"); // ConcurrentModificationException
}
解決方式:
- 使用 Iterator 的 remove()
- 使用 CopyOnWriteArrayList
- 遍歷副本