Java设计模式百例 - 迭代器模式

本文源码见:https://github.com/get-set/get-designpatterns/tree/master/iterator

迭代器(Iterator)模式又叫游标(Cursor)模式,通常用于集合类型来提供一种顺序访问其中元素而又不必暴漏集合的内部结构,是一种行为模式。

关于迭代器(Iterator)我想对Java Collection有过接触的同学就不陌生,所以本文也就无需举其他例子了,看一下在Java SDK中是如何实现的就好了。

据统计,java.util.ArrayList是Java SDK中使用频率最高的类。有人说程序就是数据结构+算法,可见数据结构的重要性。我们在日常开发中,时常跟Java集合中的各种工具类打交道,对于它们,遍历元素又是家常便饭,比如:

String[] strings = new String[]{"Hello,", "Java", "Design", "Patterns."};
List<String> stringList = Arrays.asList(strings);
Iterator<String> iterator = stringList.iterator();
while (iterator.hasNext()) {
    System.out.print(iterator.next() + " ");
}

输出即:

Hello, Java Design Patterns. 

其中的Iterator就是迭代器,它有两个核心方法:

java.util.Iterator.java(不考虑Java8新增内容)

public interface Iterator<E> {
    boolean hasNext();
    E next();
}
  • hasNext()用于判断是否还有下一个元素;
  • next()用于返回下一个元素,同时“看向”这个元素的再下一个元素。

我们常用的一些Java数据结构工具:

Collection_interfaces.png

Collection是继承自Iterable,而后者的核心方法就是返回Iterator实例的iterator()方法(不考虑Java8增加的内容的话):

java.lang.Iterable.java

public interface Iterable<T> {
    Iterator<T> iterator();
}

所以我们平时使用的各种不同的ListSetQueue的具体实现,都能返回迭代器以便能够对它们中的元素进行遍历。

java.util.ArrayList为例,它的iterator()方法返回的是Iterator的其内部类的实现:

java.util.ArrayList.java

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
    // 实际存储元素的数据
    transient Object[] elementData; 
    // 元素实际个数
    private int size;
    
    ... ...
    
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        ... ...

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            ... ...
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        ... ...
    } //End of Itr
    ... ...
} //End of ArrayList

其中去掉了一些代码。ArrayList是一种数组类型的List,其内部采用一个Object[]来保存所有元素,size用来保存一共有多少个元素。

方法iterator()会返回一个内部类Itr,后者实现了Iterator接口的hasNext()next()方法。

既然是迭代遍历,那么就需要有一个变量能够记录遍历到哪个元素了,这里Itr.cursor就是用来记录迭代索引的变量。每次调用hasNext()判断后边是否还有元素的时候,其实就是比较这个索引的值是否和size相等;每次调用next()返回下一个元素,其实就是返回elementData[cursor]并让cursor自增以指向下一个元素。

这就是迭代器模式,如果去掉各种接口和类的继承关系,简单来说:

iterator-diagram.png

迭代器模式是为集合类的事物服务的,因此类关系就很好说了:一边是集合,一边是迭代器,集合能够返回迭代器,迭代器能够遍历集合。 出于面向接口的更加灵活的模式设计,集合和迭代器均有抽象层(接口或抽象类)以及具体实现类。

最后,我们再回头看一下本文最初的例子:

Iterator<String> iterator = stringList.iterator();
while (iterator.hasNext()) {
    System.out.print(iterator.next() + " ");
}

这四行就是迭代器模式的典型用法。iterator可能是一个ArrayList返回的,可能是一个HashSet返回的,我们都不care,只要获取到迭代器,我们就可以“无脑流”一路hasNext() + next(),这就是迭代器的初衷,它为集合封装了迭代遍历元素的方法,留给用户的是一套简单易用的遍历接口。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 1 场景问题# 1.1 工资表数据的整合## 考虑这样一个实际应用:整合工资表数据。 这个项目的背景是这样的,项目...
    七寸知架构阅读 2,524评论 0 53
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,485评论 0 3
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,587评论 18 399
  • 一.集合框架 1.集合框架(对象数组的概述和使用) a.案例演示 * 需求:我有5个学生,请把这个5个学生的信息存...
    梦游的沙师弟阅读 538评论 0 1
  • 杜绝团队中出现负能量。 这是红线!
    复苏森林阅读 67评论 0 1