Iterator接口(迭代器)


前言

  • 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对象,实现了Iterator 接口或ListIterator接口。
  • 迭代器,使你能够通过循环来得到或删除集合的元素。ListIterator 继承了Iterator,以允许双向遍历列表和修改元素。

原理

  • 在获取迭代器的时候,会创建一个集合的副本。同时会创建一个指针指向迭代器迭代集合的其实位置。

方法

  1. hasNext() :该方法会判断集合对象是否还有下一个元素,如果已经是最后一个元素则返回false。
  2. next():把迭代器的指向移到下一个位置,同时,该方法返回下一个元素的引用。
  3. remove() 从迭代器指向的集合中移除迭代器返回的最后一个元素。
public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("!");
Iterator<String> ite = list.iterator();
//判断下一个元素之后是否有值
while(ite.hasNext()){
System.out.println(ite.next());
}
}
}

异常

ConcurrentModificationException异常

异常名:并发修改异常

产生原因:在使用迭代器遍历集合元素的同时对集合元素进行了操作时抛出此异常

解决办法:

使用普通for循环遍历

使用List特有的迭代器遍历


public class Test {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("张三");
c.add("李四");
c.add("王五");
Iterator<String> it = c.iterator();
while(it.hasNext()){
//必须是接收it.next(),不然会死循环。
Object obj = it.next();
String s = (String)obj;
if(s.contains("李四")){
// 最后会报ConcurrentModificationException异常
c.add("王五");
}
System.out.println(s);
}
}
}

使用foreach也会出现同样的异常:

	}
for (Object object : c) {
String s = (String)object;
if (s.contains("李四")) {
c.add("王五");
}
System.out.println(s);
}

因为foreach遍历的本质就是使用iterator迭代器遍历。

注意:

在迭代的时候是可以删除元素的。因为会使用iterator中的remove。

看一下ArrayList中iterator重写的源码就明白了。

源码:

 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
int expectedModCount = modCount; public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
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];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} @Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

在ArrayList内部定义了一个内部类Itr,该类实现了Iterator接口。

  在Itr中,有三个变量分别是

  cursor:表示下一个元素的索引位置

  lastRet:表示上一个元素的索引位置

  expectModCount:预期被修改的次数

  public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
 final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}

在执行remove操作时,会先执行checkForComodification(),判断集合的修改次数是否合法,然后会执行ArrayList的remove()方法,该方法会将modCount值加1,这里我们将expectedModCount=modCount,使之保持统一。

iterator和for循环的区别:

从数据结构角度分析,for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator适合访问链式结构,因为迭代器是通过next()来定位的.可以访问没有顺序的集合.


以上

@Fzxey

Iterator接口(迭代器)的更多相关文章

  1. Iterator接口(迭代器)的使用

    Iterator接口(迭代器) 前言 在程序开发中,经常需要遍历集合中的所有元素.针对这种需求,JDK专门提供了一个接口java.util.Iterator.Iterator接口也是Java集合中的一 ...

  2. Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

    Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器 ...

  3. PHP:Iterator(迭代器)接口和生成器

    迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...

  4. Java之Iterator接口(遍历单列集合的迭代器)

    Iterator接口概述 在程序开发中,经常需要遍历集合中的所有元素.针对这种需求,JDK专门提供了一个接口java.util.Iterator . Iterator 接口也是Java集合中的一员,但 ...

  5. php迭代器Iterator接口

    以前也看过迭代器Iterator接口,感觉不如yied好用,因此实际工作中并没有用到过. 今天看了一篇网上的博客(https://www.cnblogs.com/wwjchina/p/7723499. ...

  6. 详解 迭代器 —— Iterator接口、 ListIterator接口 与 并发修改异常

    (请关注 本人"Collection集合"博文--<详解 Collection集合>) Iterator接口(迭代器): 概述: 对 collection 进行迭代的迭 ...

  7. Iterator接口介绍和迭代器的代码实现

    定义:Iterator接口是Java集合框架中的一员. 作用:Collection接口与Map接口主要用于存储元素. 常用方法:  boolen hasNext();    //判断游标右边是否还有元 ...

  8. SPL之Iterator(迭代器)接口

    前言:SPL是用于解决典型问题(standard problems)的一组接口与类的集合. <?php /** * Class MyIterator * 在 PHP 中,通常情况下遍历数组使用 ...

  9. Collections+Iterator 接口 | Map+HashMap+HashTable+TreeMap |

    Collections+Iterator 接口 1. Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询 ...

随机推荐

  1. mysql 安装 linux系统下

    1.先检查是否安装过mysql,如果没有可进行下面的操作. 2.下载mysql的安装包 cd /usr/local    到这个目录下 mkdir mysql    新建一个mysql文件夹 cd m ...

  2. Graph图总结

    将COMP20003中关于Graph的内容进行总结,内容来自COMP20003,中文术语并不准确,以英文为准. Graph G = {V, E} 顶Vertices V: can contain in ...

  3. Python----Kernel SVM

    什么是kernel Kernel的其实就是将向量feature转换与点积运算合并后的运算,如下, 概念上很简单,但是并不是所有的feature转换函数都有kernel的特性. 常见kernel 常见k ...

  4. 播放包含flash内容的网页或flash内容, 无法显示相应flash内容

    问题描述 通过Messenger发布的html5网页到player, 如下图所示: 布局播放效果: 解决办法 从Cnario Player菜单栏打开Setting>>Canvas Cont ...

  5. CentOS系统版本的查看方法

    CentOS系统版本的查看方法 查看操作系统版本 1 [root@aliyun ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-4.1-noa ...

  6. vue 倒计时组件

    <template> <span> <i v-text="msg"></i> </span></template& ...

  7. jquery ajax几种书写方式的总结

    Ajax在前端的应用极其广泛,因此,我们有必要对其进行总结,以方便后期的使用. AJAX优点: 可以异步请求服务器的数据,实现页面数据的实时动态加载, 在不重新加载整个页面的情况下,可以与服务器交换数 ...

  8. Java8 list转map 坑

    Map<String , SonCargosForm> orderCargosMap = sonTemporaryForm.getOrderCargosList().stream() .c ...

  9. NC 命令引用了一个高手的文章做收藏

    什么是nc nc是netcat的简写,有着网络界的瑞士军刀美誉.因为它短小精悍.功能实用,被设计为一个简单.可靠的网络工具 nc的作用 (1)实现任意TCP/UDP端口的侦听,nc可以作为server ...

  10. Luogu4492 [HAOI2018]苹果树 【动态规划】

    题目分析: 思路不难想,考虑三个dp状态$f,g,d$. $g[i]$表示有$i$个点的堆的数量 $d[i]$表示有$i$个点的情况下所有的方案数中点到根的距离和 $f[i]$表示要求的答案. 不难发 ...