一、Java中有一个设计模式是迭代器模式

1.迭代器模式定义

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。

2.迭代器模式概述

Java集合框架的集合类,我们有时候称之为容器。容器的种类有很多种,比如ArrayList、LinkedList、HashSet...,每种容器都有自己的特点,ArrayList底层维护的是一个数组;LinkedList是链表;HashSet依赖的是哈希表,每种容器都有自己特有的数据结构。

因为容器的内部结构不同,在不清楚容器内部结构的情况下很难知道怎样去遍历一个容器中的元素,所以为了简化容器内的元素操作,Java引入了迭代器模式。

迭代器模式把访问逻辑从不同类型的集合类中抽取出来,从而避免想外部暴露集合的内部结构。

3.迭代器模式的角色构成

1)迭代器角色(Iterator):定义遍历元素需要的方法,一般来说会有三个方法:

next():取得下一个元素

hasNext():判断是否遍历结束(是否有下一个元素)

remove():移除当前对象

2)具体迭代器角色(Concrete Iterator):实现迭代器接口中定义的方法,完成集合的迭代。

3)容器角色(Aggregate):一般是一个接口,提供一个iterator()方法,例如Java中的Collection接口,List接口,Set接口等。

4)具体容器角色(ConcreteAggregate):抽象容器的具体实现类,例如List接口的有序列表实现ArrayList,List接口的链表实现LinList,Set接口的哈希列表的实现HashSet等。

4.迭代器模式应用的场景及意义

1)访问一个聚合对象的内容而无需暴露它的内部表示。

2)支持对聚合对象的多种遍历。

3)为遍历不同的聚合结构提供一个统一的接口。

二、迭代的实现(原理、源码)

1.java.util.Iterator

在Java中Iterator是一个接口,它只提供了迭代的基本规则。在JDK中它是这样定义的:对Collection进行迭代的迭代器。

迭代器取代了Java Collection Framework中的Enumeration。

迭代器与枚举有两点不同:

1)迭代器在迭代期间可以从集合中移除元素。

2)方法名得到了改进,Enumeration的方法名称都比较长。

接口定义:

packagejava.util;public interface Iterator{boolean hasNext(); //判断是否存在下一个对象元素

E next();//获取下一个元素

void remove(); //移除元素

}

2.Iterable

Java中还提供了一个Iterable接口,Iterable接口实现的功能是返回一个迭代器,我们常用的实现了该接口的子接口有:Collection、List、Set等。该接口的iterator()方法返回一个标注你的Iterator实现。实现Iterable接口允许对象成为Foreach语句的目标,然后就可以通过Foreach语句来遍历你的底层序列。

Iterable接口包含一个能产生Iterator对象的方法,并且Iterable被Foreach用来在序列中移动。因此如果创建了实现Iterable接口的类,都可以将它用在Foreach循环语句中。

Iterable接口的具体实现:

Package java.lang;importjava.util.Iterator;public interface Iterable{

Iteratoriterator();

}

使用Foreach遍历集合:

List names = new ArrayList<>();

list.add("张三");

list.add("李四");

list.add("王五");

list.add("赵六");for(String name : names) {

System.out.println(name);

}

可以看出使用Foreach语句遍历集合的优势在于代码更加的简洁,更不容易出错,不用关心下标的起始值和终止值。

3.Iterator遍历时不可以删除集合中的元素的问题

在使用Iterator的时候禁止对所遍历的容器进行改变其大小结构的操作。例如:在使用Iterator进行迭代时,如果堆集合进行了add、remove操作就会出现ConcurrentModificationException异常。

List names = new ArrayList<>();

list.add("张三");

list.add("李四");

list.add("王五");

list.add("赵六");//使用迭代器遍历ArrayList集合

Iterator iterator =list.iterator();while(iterator.hasNext()){

Object obj=iterator.next();if ("李四".equals(obj)){

list.remove(obj);

}

}

因为在你迭代之前,迭代器已经被通过list.itertor()创建出来了,如果在迭代的过程中,又对list进行了改变其容器大小的操作,那么Java就会给出异常,因为此时Iterator对象已经无法主动同步list做出的改变,Java会认为你做出这样的操作是线程不安全的,就会抛出异常。

Iterator的实现源码:

private class Itr implements Iterator{int cursor; //index of next element to return

int lastRet = -1; //index of last element returned; -1 if no such element returned

int expectedModCount =modCount;public booleanhasNext() {return cursor !=size;

}

@SuppressWarnings("unchecked")publicE next() {

checkForComodification();int i =cursor;if (i >=size)throw newNoSuchElementException();

Object[] elementData= ArrayList.this.elementData;if (i >=elementData.length)throw newConcurrentModificationException();

cursor= i + 1;return (E) elementData[lastRet =i];

}public voidremove() {if (lastRet < 0)throw newIllegalStateException();

checkForComodification();try{

ArrayList.this.remove(lastRet);

cursor=lastRet;

lastRet= -1;

expectedModCount=modCount;

}catch(IndexOutOfBoundsException ex) {throw newConcurrentModificationException();

}

}final voidcheckForComodification() {if (modCount !=expectedModCount)throw newConcurrentModificationException();

}

}

通过查看源码发现原来检查并抛出异常的是checkForComodification()方法。

在ArrayList中,modCount是当前集合的版本号,每次修改(增、删)集合都会加1;expectedModCount是当前迭代器的版本号,在迭代器实例化时初始化为modCount。我们看到在该方法中就是验证这两个值是否相等,所以当你在调用ArrayList.add()或者ArrayLit.remove()时,只更新了modCount的状态,而迭代器中的expectedModCount未同步,因此才会导致再次调用Iterator.next()方法的时候抛出异常。但是为什么使用Iterator.remove()就没有问题呢,通过源码的第32行发现,在Iterator的remove()中同步了expectedModCount的值,所以当你下次再调用next()的时候,检查不会抛出异常。

使用该机制的主要目的是为了实现ArrayList中的快速失败机制(fail-fast),当多个线程对Collection进行操作时,若其中某一个线程通过Iterator遍历集合时,该集合的内容被其他线程所改变,则会抛出ConcurrentModificationException异常。

所以要保证在使用Iterator遍历集合的时候不出错误,就应该保证在遍历集合的过程中不会对集合产生结构上的修改。

上面我们说了实现了Iterable接口的类就可以通过Foreach语句遍历,那是因为Foreach要依赖于Iterable接口返回的Iterator对象,所以从本质上来讲,Foreach其实就是在使用迭代器,在使用Froeach遍历的时候对集合的结构进行修改,和在使用Iterator遍历时堆集合结构进行修改本质上是一样的。所以同样的也会抛出异常,执行快速失败机制。

三、迭代的使用(遍历)

迭代器遍历,就是将集合中的数据放到一个容器中排成一排,Iterator有一个游标,开始遍历时,游标在第一个元素的前面,通过调用Iterator.next()方法,将游标向后移动一位,Iterator.hasNext()方法则是判断游标后面还有没有可以迭代的元素。

1.迭代器(Iterator)遍历List

List list = new ArrayList<>();

list.add("a");

list.add("b");

Iterator iterator =list.iterator();while(iterator.hasNext()){

String next=iterator.next();

System.out.println(next);

}

2.迭代器(Iterator)遍历Set

因为Set是无序的,所以for循环无法遍历Set,只能用迭代器遍历,导致后面统一用迭代器遍历集合,这就是迭代器的产生(手动滑稽)。

Set set = new HashSet<>();

set.add("a");

set.add("b");

Iterator iterator =set.iterator();while(iterator.hasNext()){

String next=iterator.next();

System.out.println(next);

}

3.迭代器(Iterator)遍历Map

Map中是存放的是键值对,不是像List或者Set那样存放单一元素,所以我们需要先将Map作为单一元素放到Set中,使用JDK中Map提供的entrySet()方法。

Map map = new HashMap<>();

Set> entries =map.entrySet();

Iterator> iterator =entries.iterator();while(iterator.hasNext()){

Map.Entry next =iterator.next();

System.out.println(next);

}

java集合迭代器_java集合迭代器相关推荐

  1. java 集合 接口_Java集合之Collection接口

    1 - Java集合介绍 /* 1. 一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象 的操作,就要对对象进行存储. 2. 另一方面,使用Array存储对象方面具有一些弊 端,而 ...

  2. Java集合学习_Java集合学习(适合新手)

    集合框架 由⼀组类和接⼝组成的⼀个体系. Collection 集合框架 最基本的接⼝,⼀个 Collection 可以存储⼀组⽆序.不唯⼀的对象,实际开发中不会直接使⽤ Collection 进⾏开 ...

  3. java for 迭代器_Java基础-迭代器Iterator与语法糖for-each

    迭代器Iterator与语法糖for-each 一.为什么需要迭代器 设计模式迭代器 迭代器作用于集合,是用来遍历集合元素的对象.迭代器不是Java独有的,大部分高级语言都提供了迭代器来遍历集合.实际 ...

  4. java list 接口_Java 集合 List接口

    [TOC] List接口 概述有序的 collection(也称为序列).此接口的用户可以对列表中每个元素的插入位置进行精确地控制.用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的 ...

  5. java集合总结_java集合小总结

    java集合就是一个容器. 1.     集合概述 l       为了保存不确定的数据,或者对象,以及保存具有映射关系的数据. l       所有的集合类都位于java.util包下. 1.1.  ...

  6. java集合系列_Java集合系列01-Java集合概述

    1.Java集合基本概念 在编程中,常常需要集中存放多个数据.从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量,因为数组长度在初始化时指定,意味着只能保存 ...

  7. java集合继承_java集合继承关系

    数组虽然也可以存储对象,但长度是固定的:集合长度是可变的,数组中可以存储基本数据类型,集合只能存储对象. 集合类的特点:集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象. 上述类图中, ...

  8. java集合示例_Java集合的addAll()方法和示例

    集合类addAll()方法addAll()方法在java.lang包中可用. addAll()方法用于将所有给定元素(ele)放入给定集合(co). addAll()方法是一个静态方法,可以使用类名进 ...

  9. java族谱设计_Java集合族谱总结

    集合族谱核心成员 集合族谱核心成员 所有的集合类,都实现了Iterator接口,这是用于遍历集合中元素的接口:Java集合框架核心是两个类型的容器,一种是集合(Collection),存储单一元素,一 ...

最新文章

  1. 中自苏研院2021招聘季开始啦!
  2. GdiPlus[28]: IGPPen: 建立复合画笔
  3. c语言打开外部doc文件,C语言-内部函和外部函数.doc
  4. Python 3.6学习笔记(一)
  5. 准确率(Accuracy) | 查准率(Precision) | 查全率(Recall)
  6. C#:泛型(Generic)
  7. DedeCMS自定义表单制作和调用办法
  8. 男生计算机学校,杭州2021年男生读什么计算机学校
  9. 五分钟搭建起一个包含CRUD功能的JqGrid表格
  10. [转帖]Windows下cwRsyncServer双机连续同步部署
  11. 即席查询—Presto
  12. 凸优化 - 3 - Jensen不等式、共轭函数、Fenchel不等式
  13. 红警2科技时代2.7正式版
  14. THANK YOU FOR YOUR CONCERN, SIOBAN AND ANTHONY
  15. 计蒜客 17115 2017 ICPC 西安网络赛 B Coin
  16. 使用有赞商城API新增商品
  17. 约瑟夫环(51nod)
  18. 对计算机会计上机课的心得,会计电算化的心得体会
  19. Shortest Path
  20. JTR(John The Ripper)的ssh密钥破解记录

热门文章

  1. Mysql学习总结(61)——MySQL优化之DBA级优化整理汇总
  2. Docker学习总结(21)——Docke网络bridge详解
  3. Mysql学习总结(43)——MySQL主从复制详细配置
  4. Linux学习总结(11)——Linux文件查找
  5. 极客c语言课程设计,c语言课程设计之实习报告共5天完整.doc
  6. springboot忽略证书_SpringBoot中通过java代码实现忽略SSL证书
  7. sourceforge加速下载_CentOS 7下使用mwget加速wget
  8. Java中的String.hashCode()方法可能有问题?
  9. Spring Cloud构建微服务架构—服务网关过滤器
  10. 致敬各位10年阿里的前端开发