### 7. 迭代器的线程安全
Java 提供了多种集合类,有些是线程安全的,有些则不是。对于非线程安全的集合类,在多线程环境下使用迭代器时需要特别小心。
#### 7.1 `ConcurrentModificationException`
在迭代过程中,如果集合的结构被修改(除了通过迭代器自身的 `remove` 方法),则迭代器会抛出 `ConcurrentModificationException`。这是一种快速失败机制,防止迭代器在不一致状态下运行。
```java
import java.util.ArrayList;
import java.util.Iterator;
public class ConcurrentModificationExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
try {
for (String element : list) {
if (element.equals("B")) {
list.remove(element);
}
}
} catch (ConcurrentModificationException e) {
System.out.println("Caught ConcurrentModificationException");
}
}
}
```
#### 7.2 使用 `CopyOnWriteArrayList`
对于需要在遍历过程中安全地修改集合的场景,可以使用线程安全的集合类,如 `CopyOnWriteArrayList`。这种集合在每次修改时都会创建一个新的底层数组,因此适合读多写少的场景。
```java
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if (element.equals("B")) {
list.remove(element);
}
}
System.out.println("List after removal: " + list);
}
}
```
### 8. 自定义迭代器
有时需要为自定义集合类实现迭代器。为了实现 `Iterable` 接口,必须实现 `
```java
java.util.Iterator` 接口并提供 `iterator()` 方法。下面是一个简单的自定义集合类及其迭代器的示例:
#### 8.1 自定义集合类
首先,我们创建一个简单的自定义集合类 `MyCollection`,该类内部使用数组来存储元素。
```java
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyCollection<T> implements Iterable<T> {
private T[] items;
private int size = 0;
private static final int DEFAULT_CAPACITY = 10;
@SuppressWarnings("unchecked")
public MyCollection() {
items = (T[]) new Object[DEFAULT_CAPACITY];
}
public void add(T item) {
if (size == items.length) {
resize();
}
items[size++] = item;
}
private void resize() {
@SuppressWarnings("unchecked")
T[] newItems = (T[]) new Object[items.length * 2];
System.arraycopy(items, 0, newItems, 0, items.length);
items = newItems;
}
@Override
public Iterator<T> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<T> {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < size;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items[currentIndex++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
public static void main(String[] args) {
MyCollection<String> collection = new MyCollection<>();
collection.add("Item1");
collection.add("Item2");
collection.add("Item3");
for (String item : collection) {
System.out.println(item);
}
}
}
```
### 9. 迭代器的优缺点
#### 9.1 优点
1. **统一访问方式**:迭代器提供了一种统一的方式来遍历各种集合,而无需了解其底层实现。
2. **简化代码**:使用迭代器可以简化遍历代码,避免手动管理索引等复杂操作。
3. **增强的安全性**:迭代器在遍历过程中,可以检测并防止集合的并发修改,从而提高安全性。
#### 9.2 缺点
1. **性能开销**:迭代器会增加一定的性能开销,尤其是在大量元素的遍历过程中。
2. **有限的操作**:标准迭代器接口只支持有限的集合操作,如遍历和删除,不支持添加和修改操作(除了 `ListIterator`)。
3. **实现复杂**:对于自定义集合类,实现迭代器接口可能会增加代码的复杂性。
### 10. 迭代器的最佳实践
1. **优先使用增强的 for 循环**:对于简单的遍历操作,优先使用增强的 for 循环,因为它内部已经使用了迭代器。
2. **注意并发修改**:在多线程环境中使用迭代器时,要注意并发修改问题,可以使用线程安全的集合类或适当的同步机制。
3. **实现 `Iterable` 接口**:自定义集合类时,实现 `Iterable` 接口,提供迭代器支持,使其能够被增强的 for 循环使用。
4. **异常处理**:在实现自定义迭代器时,注意处理 `NoSuchElementException` 和 `UnsupportedOperationException` 异常。
### 11. 总结
迭代器是Java集合框架中一个重要的组件,提供了遍历集合的一种标准化方式。通过实现 `Iterator` 接口,集合类可以提供一个迭代器,允许用户以统一的方式访问其元素。Java中的迭代器不仅支持基本的遍历操作,还提供了一些修改集合的方法。通过 `ListIterator`,可以实现更丰富的列表操作。
迭代器在实际开发中非常有用,不仅简化了代码,还提高了代码的可读性和可维护性。在多线程环境中,使用迭代器还可以提高程序的安全性。通过学习和掌握迭代器的使用和实现,可以更好地理解Java集合框架,提高编程能力。