迭代器大家应该都不陌生了。作为Java程序员,遍历集合也是我们学习Java知识的开始。遍历集合的方式也有很多种,比如for循环、while循环、foreach循环、Iterator等,这里的Iterator就是我们设计模式中的迭代器模式。这次要和大家分享的设计模式就是迭代器模式。虽然很多语言直接将Iterator封装到基础工具类中,但是你了解它的特点吗?这个大纲中迭代器的定义大家都很熟悉了,那么什么是迭代器呢?它的目的是什么?定义:我们可以用同样的方式来处理集合,无论是列表还是数组,它都提供了一种在不暴露其内部结构的情况下迭代其元素的机制,更重要的是,不同类型的集合可以使用相同的统一机制,这称为迭代器模式。目的:提供一种在不暴露其内部实现的情况下顺序遍历聚合对象元素的方法。从上面的定义看设计模式之美的分析图:Aggregate(抽象容器):负责提供创建具体迭代器角色的接口,对应java.util.Collection接口。Iterator(抽象迭代器):迭代器的抽象类,定义了遍历容器对象的操作和返回对象的操作ConcreteAggregate(具体容器):主要实现不同的内部结构。但是公开处理遍历容器的具体迭代器。ConcreteIterator(具体迭代器):处理具体具体容器类的具体迭代器。事实上,对于每个特定于容器的容器,必须实现特定的迭代器。整个图看起来其实有两个东西,一个容器和一个迭代器。这次就不列出代码实现了。直接写一个迭代器,我们再测试一下。主要是理解迭代器的作用:能够遍历集合中的所有元素,而不暴露集合的底层表示(列表、栈、树等)/添加元素voidadd(Objectobject);//移除元素voidremove(Objectobject);//迭代器Iteratoriterator();}根据上面的类图,首先创建一个抽象容器,定义几个基本的元素增删方法,迭代器publicinterfaceIterator{//判断是否容器有值booleanhasNext();//将光标拉到下一个指针voidnext();//当前遍历的数据EcurrentItem();}接下来尝试在publicclassConcreteAggregateimplementsAggregate{privateArrayListarrayList=中创建一个抽象迭代器来遍历容器数据newArrayList();@Overridepublicvoidadd(Objectobject){this.arrayList.add(object);}@Overridepublicvoidremove(Objectobject){this.arrayList.remove(object);}@OverridepublicIterator(newConcreteIterator(){returnthis.arrayList);}}开始定义我们具体的容器,内部设置一个ArrayList容器来存放数据,当然你也可以在这里改成其他容器,比如使用Vector或者其他的栈、树、图等。publicclassConcreteIteratorimplementsIterator{privateintcursor;//游标privateArrayListarrayList;publicConcreteIterator(ArrayListarrayList){this.cursor=0;this.arrayList=arrayList;}@OverridepublicbooleanhasNext(){if(this.cursor==this.arrayList.size()){returnfalse;}returntrue;}@Overridepublicvoidnext(){cursor++;System.out.println(cursor+"cursor");}@OverridepublicEcurrentItem(){if(cursor>=arrayList.size()){thrownewNoSuchElementException();}Ee=(E)arrayList.get(cursor);this.next();returne;}//测试demopublicstaticvoidmain(String[]args){Aggregateaggregate=newConcreteAggregate();aggregate.add("java");aggregate.add("c++");aggregate.add("php");aggregate.add("敖丙");Iteratoriterator=aggregate.iterator();while(iterator.hasNext()){System.out.println(iterator.currentItem());}//result:1java//2c++//3php//4敖丙}}最后实现具体的迭代器,在currentItem中根据遍历游标,获取数组中的值,在main方法中测试demo。上面是一个简单的手动迭代器。其实我们还可以有其他特殊的玩法,比如如何实现暂停遍历Wait,只有了解了内部实现,才能改造出满足当前需求的业务代码。Java中的迭代器也有Java中的迭代器。java.util.Iterator类和java.util.Collection是迭代器和容器的典型示例。接下来我们看一下具体的源码。会抛出NoSuchElementException异常信息,上面手动异常也是基于此。Java中常见的List、Set、Queue都是extendCollection(容器),而Collection定义了迭代器Iterator,这也是可以直接向上使用的原因。Java集合分析上面我们看了Java中的迭代器,不知道大家有没有注意到,我们在使用迭代器的时候,不能再对集合进行增减操作,否则会抛出ConcurrentModificationException,那么问题来了,为什么有这个异常信息吗?看过ArrayList源码的同学都知道,底层是数据结构中的数组结构,那么我们看下图结构,假设我们现在遍历当前数组。从第一步执行到第二步时,一切运行正常。假设现在执行第二步,第三步开始时删除java元素。为了保持存储数据的连续性,当java数据被删除时,数组元素会发生迁移。所以正常的第3步应该是遍历到aobing元素,变成当前数组元素已经是aobing。这样一来,数组不会被aobing遍历,会因为数据迁移而丢失。还要假设后面添加的元素可以按照后向迁移遍历,那么如果插入的数据在遍历的数据之前呢?这样,整个遍历就变得不可预测了。publicstaticvoidmain(String[]args){Listaggregate=newArrayList();aggregate.add("java");aggregate.add("c++");aggregate.add("php");aggregate.add("AoBing");Iteratoriterator=aggregate.iterator();while(iterator.hasNext()){iterator.remove();//添加这行代码java.lang.IllegalStateExceptionSystem.out.println(iterator.next());iterator.remove();//正常}}再看这个测试demo,同样调用了remove方法,不同地方结果不一样,恰好印证了上面反映的问题上图,所以我们要解决这个问题,要么遍历时不允许添加或删除元素,要么添加或删除元素后让遍历报错。通过上面的例子,你已经了解了迭代器的原理和实现。您可以根据自己的需要修改迭代器。公司自己的一些框架或工具是从现有的框架源代码改造而来的。迭代器的优点:迭代器模式将复杂的数据结构封装在集合内部,无需关心需要遍历的对象。本着单一职责原则和开闭原则,可以控制遍历、暂停或继续总结迭代器设计模式。我个人认为在我们业务场景中我写的代码中是比较少见的。至少到目前为止,我还没有找到任何好的。这种模式可以用在业务场景中,这里就不给大家举个业务代码改造的例子了。(毕竟不能因为设计模式而强求设计)把迭代器分享给大家主要是为了让大家了解Java集合遍历是如何实现的,从而提高我们阅读源码的能力未来并提高我们的设计能力。动态代理设计模式后面会和大家聊,其他的模式我就不详细说了,因为不是很常用,所以做一个总结分享给大家,以供大家理解。今天的迭代器模式到此结束。我是敖丙你知道的越多,你不知道的就越多。下次再见!!!