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. antd pro 分支

    添加图片 这两种都可以 form表单问题 1 @Form.create() 这是绑定表单和组件,必须有,这样就能从this.props 中找到Form了 2 Select 要写initialValue ...

  2. postman Installation has failed: There was an error while installing the application. Check the setup log for more information and contact the author

    Error msg: Installation has failed: There was an error while installing the application. Check the s ...

  3. Centos7安装配置Nginx

    Nginx 安装 系统平台:CentOS 7.4 64位. 一,安装编译工具及文件 yum -y install make zlib zlib-devel gcc-c++ libtool openss ...

  4. Quill 富文本编辑器

    Quill 富文本编辑器 https://quilljs.com/ https://github.com/quilljs/quill https://github.com/quilljs/awesom ...

  5. 为什么qt成为c++界面编程的第一选择

    为什么qt成为c++界面编程的第一选择 一.前言 为什么现在QT越来越成为界面编程的第一选择,笔者从事qt界面编程已经有接近8年,在这之前我做C++界面都是基于MFC,也做过5年左右.当时为什么会从M ...

  6. 自动化测试(web测试selenium框架)

    什么是selenium? 一个用于Web应用程序测试的工具直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safa ...

  7. 【CF1152F】Neko Rules the Catniverse(动态规划)

    [CF1152F]Neko Rules the Catniverse(动态规划) 题面 CF 题解 我们先考虑一个需要扫一遍所有位置的做法. 那么状态一定是\(f[i]\)然后什么什么表示考虑到当前第 ...

  8. POJ2975 Nim 【博弈论】

    DescriptionNim is a 2-player game featuring several piles of stones. Players alternate turns, and on ...

  9. Motorola和Intel格式报文解析的区别

      结论:无论用的Motorola,还是Intel格式,只在单个信号跨字节时解析才有区别. 先看下Vector的CANoe中dbc编辑器是如何呈现报文的: 图1 CAN报文中byte与bit顺序 从图 ...

  10. http验证

    read -p "输入要添加的用户名: " USERNAME read -p "输入密码: " PASSWD printf "$USERNAME:$( ...