Saul's blog Saul's blog
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)

Saul.J.Wu

立身之本,不在高低。
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)
  • Java入门基础

  • Java核心基础

  • 设计模式

    • 概念
    • 创建型模式

    • 结构型模式

    • 行为型模式

      • 责任链
      • 命令
      • 解释器
      • 迭代器
        • 概念
        • 如何实现?
        • 小结
      • 中介
      • 备忘录
      • 观察者
      • 状态
      • 策略
      • 模板方法
      • 访问者
  • Web开发

  • SpringBoot

  • 微服务

  • Elasticsearch

  • 运维

  • 后端
  • 设计模式
  • 行为型模式
SaulJWu
2021-02-10

迭代器

# 概念

提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

迭代器模式(Iterator)实际上在Java的集合类中已经广泛使用了。我们以List为例,要遍历ArrayList,即使我们知道它的内部存储了一个Object[]数组,也不应该直接使用数组索引去遍历,因为这样需要了解集合内部的存储结构。如果使用Iterator遍历,那么,ArrayList和LinkedList都可以以一种统一的接口来遍历:

List<String> list = ...
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
    String s = it.next();
}
1
2
3
4

实际上,因为Iterator模式十分有用,因此,Java允许我们直接把任何支持Iterator的集合对象用foreach循环写出来:

List<String> list = ...
for (String s : list) {

}
1
2
3
4

然后由Java编译器完成Iterator模式的所有循环代码。

# 如何实现?

虽然我们对如何使用Iterator有了一定了解,但如何实现一个Iterator模式呢?我们以一个自定义的集合为例,通过Iterator模式实现倒序遍历:

public class ReverseArrayCollection<T> implements Iterable<T> {
    // 以数组形式持有集合:
    private T[] array;

    public ReverseArrayCollection(T... objs) {
        this.array = Arrays.copyOfRange(objs, 0, objs.length);
    }

    public Iterator<T> iterator() {
        return ???;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

实现Iterator模式的关键是返回一个Iterator对象,该对象知道集合的内部结构,因为它可以实现倒序遍历。我们使用Java的内部类实现这个Iterator:

public class ReverseArrayCollection<T> implements Iterable<T> {
    private T[] array;

    public ReverseArrayCollection(T... objs) {
        this.array = Arrays.copyOfRange(objs, 0, objs.length);
    }

    public Iterator<T> iterator() {
        return new ReverseIterator();
    }

    class ReverseIterator implements Iterator<T> {
        // 索引位置:
        int index;

        public ReverseIterator() {
            // 创建Iterator时,索引在数组末尾:
            this.index = ReverseArrayCollection.this.array.length;
        }

        public boolean hasNext() {
            // 如果索引大于0,那么可以移动到下一个元素(倒序往前移动):
            return index > 0;
        }

        public T next() {
            // 将索引移动到下一个元素并返回(倒序往前移动):
            index--;
            return array[index];
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

使用内部类的好处是内部类隐含地持有一个它所在对象的this引用,可以通过ReverseArrayCollection.this引用到它所在的集合。上述代码实现的逻辑非常简单,但是实际应用时,如果考虑到多线程访问,当一个线程正在迭代某个集合,而另一个线程修改了集合的内容时,是否能继续安全地迭代,还是抛出ConcurrentModificationException,就需要更仔细地设计。

# 小结

Iterator模式常用于遍历集合,它允许集合提供一个统一的Iterator接口来遍历元素,同时保证调用者对集合内部的数据结构一无所知,从而使得调用者总是以相同的接口遍历各种不同类型的集合。

帮我改善此页面 (opens new window)
上次更新: 2021/02/16, 02:24:29
解释器
中介

← 解释器 中介→

最近更新
01
zabbix学习笔记二
02-28
02
zabbix学习笔记一
02-10
03
Linux访问不了github
12-08
更多文章>
Theme by Vdoing | Copyright © 2020-2022 Saul.J.Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式