你有没有掉进去过这些 迭代器 的 “陷阱“

简介: 你有没有掉进去过这些 迭代器 的 “陷阱“

一、迭代数组或集合时的 ”陷阱“

对于集合和数组的迭代,最常用的方式就是使用 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());
        }
    }
}
复制代码

执行上述代码,输出结果如下:

2a13b19d56844b3381d05d92eb6c8ee7_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png


相关文章
|
7月前
|
存储 C++ 索引
当谈论迭代器时,我谈些什么?
当谈论迭代器时,我谈些什么?
66 1
|
编译器 C语言
C语言编程陷阱:语法陷阱
c语言要求在函数调用时即使函数不带参数,也应该包括函数列表。 是挂else问题
61 0
|
4月前
|
设计模式 程序员
故意把代码写得很烂,这样的 “防御性编程“ 可取吗?
故意把代码写得很烂,这样的 “防御性编程“ 可取吗?
|
7月前
|
存储 编译器 C语言
C陷阱:数组越界遍历,不报错却出现死循环?从内存解析角度看数组与局部变量之“爱恨纠葛”
在代码练习中,通常会避免数组越界访问,但如果运行了这样的代码,可能会导致未定义行为,例如死循环。当循环遍历数组时,如果下标超出数组长度,程序可能会持续停留在循环体内。这种情况的发生与数组和局部变量(如循环变量)在内存中的布局有关。在某些编译器和环境下,数组和局部变量可能在栈上相邻存储,数组越界访问可能会修改到循环变量的值,导致循环条件始终满足,从而形成死循环。理解这种情况有助于我们更好地理解和预防这类编程错误。
153 0
|
存储 算法 编译器
抽丝剥茧C语言(中阶)分支与循环练习
抽丝剥茧C语言(中阶)分支与循环练习
|
小程序 编译器 C语言
c++重中之重:“换个龟壳继续套娃“:运算符重载等的学习
c++重中之重:“换个龟壳继续套娃“:运算符重载等的学习
127 0
|
Python
又烧脑又炫技还没什么用,在代码里面打印自身
又烧脑又炫技还没什么用,在代码里面打印自身
208 0
又烧脑又炫技还没什么用,在代码里面打印自身
|
编译器 C++
<C++>一篇文章搞懂类和对象中常函数和常对象的实质以及避免空指针访问的小妙招
<C++>一篇文章搞懂类和对象中常函数和常对象的实质以及避免空指针访问的小妙招
163 0
|
存储 编译器 C++
C++模拟面试:宏、lambda、智能指针闲谈
C++模拟面试:宏、lambda、智能指针闲谈
211 0
C++模拟面试:宏、lambda、智能指针闲谈
|
JavaScript 数据处理
【重温基础】13.迭代器和生成器
【重温基础】13.迭代器和生成器
121 0