一、迭代数组或集合时的 ”陷阱“
对于集合和数组的迭代,最常用的方式就是使用 for 循环
和 迭代器
进行迭代。新建一个 Maven 项目 iterator-traps, 添加 junit 依赖。
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> 复制代码
在 test 包下创建测试类 com.traps.IterationTest
,用于测试 for 循环
迭代和 迭代器
迭代
for 循环迭代
当需要对一个数组进行遍历的时候,可以使用 for 循环通过数组长度,建立索引来实现迭代
public class IterationTest { @Test public void testForeachByUsingIndex(){ int[] items = new int[]{1,2,3,4}; for (int i = 0; i < items.length; i++) { System.out.println(items[i]); } } } 复制代码
执行上述代码,输出结果如下:
1 2 3 4 复制代码
for 循环可以非常简单的通过索引来循环获取数组中的每一个元素。
迭代器迭代
迭代器 Iterator
是一种用于访问集合的方法,可以用于迭代集合,Iterator
接口是 Java 迭代器中最简单的实现,Java 中的集合 Collection 接口都有一个 iterator() 方法,该方法可以返回一个 Iterator 对象,Iterator 对象本身并不存放任何元素或者对象。
迭代器
模式提供了一种方法来顺序访问一个聚合对象中的各个元素,而不保留该对象的内部表示,迭代器模式是一种对象行为型模式,其主要优点如下:
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 将遍历任务交由迭代器完成,简化了聚合类。
- 支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
- 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
- 封装性良好,为遍历不同的聚合结构提供一个统一的接口。
在 IterationTest 测试类中增加测试方法 testIterateCollections
public class IterationTest { // 其余代码保持不变 private static Collection<String> zulu = Arrays.asList("Seal A", "Seal B", "Seal C", "Seal D"); private static Collection<String> yankee = Arrays.asList("Seal Z", "Seal Y", "Seal X", "Seal W", "Seal V"); @Test public void testIterateCollections(){ for (Iterator<String> items = yankee.iterator(); items.hasNext();){ System.out.println(items.next()); } } } 复制代码
执行上述代码,输出记过如下:
Seal Z Seal Y Seal X Seal W Seal V 复制代码
但是当嵌套迭代两个集合时,会出现异常
@Test public void testNestIterateCollections(){ for (Iterator<String> items = yankee.iterator(); items.hasNext();){ for (Iterator<String> eles = zulu.iterator(); eles.hasNext();){ System.out.println(items.next() + " " + eles.next()); } } } 复制代码
执行上述代码,输出记过如下:
Seal Z Seal A Seal Y Seal B Seal X Seal C Seal W Seal D Seal V Seal A java.util.NoSuchElementException at java.util.AbstractList$Itr.next(AbstractList.java:364) ..................... 复制代码
这是应为对于外部集合来说, next 调用次数太多,导致集合中的元素已经迭代完了还在调用 next,应该是在外部循环中调用 next 而不是在内嵌的循环中调用最外层迭代器的 next。
修改 testNestIterateCollections 方法
@Test public void testNestIterateCollections(){ for (Iterator<String> items = yankee.iterator(); items.hasNext();){ String code= items.next(); for (Iterator<String> eles = zulu.iterator(); eles.hasNext();){ System.out.println(code + " " + eles.next()); } } } 复制代码
执行上述代码,输出结果如下: