iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >Java迭代器详解,看这一篇就够了
  • 385
分享到

Java迭代器详解,看这一篇就够了

java开发语言后端 2023-08-19 16:08:26 385人浏览 薄情痞子
摘要

文章目录 🚩Java 迭代器详解📚迭代器的定义📒认识Iterator✏️类结构图✒️Iterable接口🖍️Iterator接口📃Iterat

🚩Java 迭代器详解

📚迭代器的定义

迭代器是属于设计模式之一,迭代器模式提供了一种方法来顺序访问一个聚合对象中各个元素,而不保留该对象的内部表示。

1)Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器
3)Iterator仅用于遍历集合,Iterator本身并不存放对象。

📒认识Iterator

✏️类结构图

在这里插入图片描述
通过观察类结构图的继承关系我们发现,集合的顶层接口Collection继承Iterable接口。

✒️Iterable接口

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

Iterable接口中有一个Iterator方法,它返回一个Itertator对象

🖍️Iterator接口

public interface Iterator<E> {    boolean hasNext();        E next();        default void remove() {        throw new UnsupportedOperationException("remove");    }}

📃Iterator接口的方法

返回值类型方法名功能
booleanhasNext()判断集合是否还有元素,如果返回 true 表示集合还有元素,返回 false 表示集合中没有元素;一般对集合的访问通过 while(hasNext()) 判断是否还需要遍历。
E next()获取集合中遍历的当前元素 ;一般先调用 hasNext() 方法判断是否存在元素,再调用 next() 获取元素,需要进行循环交替遍历集合中的元素。
voidremove删除集合中的元素。

📙迭代器的使用

🏷️使用迭代器遍历集合

我们用ArrayList集合存放一些整型数据做示例,然后将其集合中的元素一一遍历打印输出。

import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class TestDemo {    public static void main(String[] args) {        List<Integer> list = new ArrayList<>();        list.add(111);        list.add(222);        list.add(333);        Iterator<Integer> iterator = list.iterator();        while(iterator.hasNext()) {            int value = iterator.next();            System.out.print(value + " ");        }    }}

运行结果:
在这里插入图片描述
观察运行结果我们发现,通过迭代器我们将ArrayList集合中的元素一一打印了出来。

🔖Itertor的执行原理

在上述的示例中,迭代器是如何实现对集合的遍历呢?

⏳图示执行过程

在这里插入图片描述

⌛执行过程详解

①首先得到一个集合的迭代器Iterator iterator = list.iterator();
②进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置的元素111返回。
③再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置222的元素返回。
④再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置333的元素返回。
⑤再次进入while循环,调用hasNext()判断是否有下一个元素,返回false,循环结束。


迭代器的遍历过程中先通过hastNext()方法判断是否有下一个元素,如果存在下一个元素再调用next()方法获取元素,在这里next()方法先往后移动一个元素位置,再返回该位置的元素。因此,在调用next()方法之前必须要调用hastNext()方法进行检测;如果没有调用并且没有下一个元素,直接调用next()方法会抛出 NoSuchElementException异常

🃏生成迭代器的快捷键

一开始使用迭代器可能会觉得麻烦,但是如果用的idea编译器是有快捷键的,输入itit再回车就会直接生成。
在这里插入图片描述

📕迭代器中的remove()

⛄迭代器的remove()方法使用

Iterator接口中除了hasNext()next()方法外,还有一个remove()方法,即删除集合中的元素

如删除上述示例集合中的元素111

import java.util.ArrayList;import java.util.Iterator;import java.util.List;@SuppressWarnings({"all"})public class TestDemo {    public static void main(String[] args) {        List<Integer> list = new ArrayList<>();        list.add(111);        list.add(222);        list.add(333);        System.out.println("删除前:" + list);        Iterator<Integer> iterator = list.iterator();        while (iterator.hasNext()) {            Integer value =  iterator.next();            if(value == 111) iterator.remove();        }        System.out.println("删除后" + list);    }}

运行结果:
在这里插入图片描述

☃️迭代器遍历中调用集合revome()方法触发异常

在Java集合中,以集合ArrayList为例,在使用中可能会遇到删除的需求场景,此时如果代码书写不当,极有可能会抛出java.util.ConcurrentModificationException异常信息。
在上述示例中用Iterator调用了迭代器remove()方法,如果在使用中不小心调用了集合中的remove()方法会发生什么?

import java.util.ArrayList;import java.util.Iterator;import java.util.List;@SuppressWarnings({"all"})public class TestDemo {    public static void main(String[] args) {        List<Integer> list = new ArrayList<>();        list.add(111);        list.add(222);        list.add(333);        System.out.println("删除前:" + list);        Iterator<Integer> iterator = list.iterator();        while (iterator.hasNext()) {            Integer value =  iterator.next();            if(value == 111) list.remove(Integer.valueOf(111));        }        System.out.println("删除后" + list);    }}

运行结果:
在这里插入图片描述
运行结果中抛出java.util.ConcurrentModificationException异常信息。这是因为触发了集合中并发修改的异常 接下来我们通过源码对抛出异常的原因进行剖析。

    public Iterator<E> iterator() {        return new Itr();    }

ArrayList集合的Iterator方法中,是通过返回Itr对象来获得迭代器的。ItrArrayList的一个内部类,它实现了Iterator接口,代码如下:

   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;        Itr() {}        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();            }        }

Itr类属性

属性含义
cursor索引下标,表示下一个可以访问的元素的索引,默认值为 0
lastRet索引下标,表示上一个元素的索引,默认值为 -1
expectedModCount对集合修改的版本号,初始值为ModCount

ModCount定义在AbstractList接口中,初始值为0,定义如下:

 protected transient int modCount = 0;

ModCount是版本号,在对集合进行变更操作(增加、删除、修改等)的时候会对版本号进行 +1 操作。


结合上述代码进行抛出java.util.ConcurrentModificationException异常的解释。
①初始化ArrayList,添加三次元素,即三次调用add()方法,进行三次modCount++; 此时,m o d C o u n t = 3 , s i z e = 3 ; \color{red}{modCount = 3,size = 3;} modCount=3size=3
②初始化Iterator迭代器进行循环,此时,e x p e c t e d M o d C o u n t = m o d C o u n t = 3 , \color{red}{expectedModCount = modCount=3,} expectedModCount=modCount=3 c u r s o r = 0 , l a s t R e t = − 1 \color{red}{cursor=0,lastRet = -1} cursor=0lastRet=1
③进行hasNext判断,cursor != size;成立,进入循环
④调用next()方法,首先进行checkForComodification()校验,m o d C o u n t = = e x p e c t e d M o d C o u n t \color{red}{modCount == expectedModCount} modCount==expectedModCount,校验通过,返回值,此时l a s t R e t = 0 ; c u r s o r = 1 \color{red}{lastRet = 0;cursor = 1} lastRet=0;cursor=1

 final void checkForComodification() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();        }

⑤调用集合remove()方法,modCount++;,此时m o d C o u n t = 4 ; s i z e = 2 \color{red}{modCount = 4;size = 2} modCount=4;size=2
⑥再次调用hasNext()方法判断,cursor != size;成立,进入循环
⑦调用next()方法进行校验,m o d C o u n t ! = e x p e c t e d M o d C o u n t \color{red}{modCount != expectedModCount} modCount!=expectedModCount,校验未通过,抛出java.util.ConcurrentModificationException异常

总结:

①在使用迭代器remove()操作时,会将更新后的modCountexpectedModCount,两者会得到同步,但是在调用集合的remove()方法后,两个不会进行同步,进而导致在checkForComodification()校验时不通过,抛出java.util.ConcurrentModificationException异常。
②所以,在单线程下使用迭代器是没有问题的,但是在多线程下同时操作集合就不允许了,可以通过fail-fast快速失败机制,快速判断是否存在同时操作问题。因此,集合在多线程下使用是不安全

📗增强for循环

📫认识增强for循环

增强for循环可以代替Iterator迭代器,可以把它看做简化版的Iterator,和迭代器本质一样,其实它的底层实现就是Iterator迭代器,只能用于遍历集合或数组

📪基本语法

在这里插入图片描述

📬增强for循环的使用

import java.util.ArrayList;import java.util.List;public class TestDemo03 {    public static void main(String[] args) {        List<Integer> list = new ArrayList<>();        list.add(111);        list.add(222);        list.add(333);        System.out.println("====增强for循环遍历集合====");        for(Integer i : list) {            System.out.print(i + " ");        }        System.out.println();        System.out.println("====增强for循环遍历数组====");        int[] arr = {1,2,3,4,5,6};        for (int i : arr) {            System.out.print(i + " ");        }    }}

运行结果:
在这里插入图片描述

📭增强for循环的快捷键

与迭代器一样,增强for循环也有快捷键,输入I回车即可快速生成。
在这里插入图片描述

来源地址:https://blog.csdn.net/sheng0113/article/details/122712947

--结束END--

本文标题: Java迭代器详解,看这一篇就够了

本文链接: https://www.lsjlt.com/news/375653.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java迭代器详解,看这一篇就够了
    文章目录 🚩Java 迭代器详解📚迭代器的定义📒认识Iterator✏️类结构图✒️Iterable接口🖍️Iterator接口📃Iterat...
    99+
    2023-08-19
    java 开发语言 后端
  • Java数组看这篇就够了
    目录一、前言二、数组的定义数组定义的形式:三、数组的初始化方式:1.动态初始化2.静态初始化四、索引访问数组五、数组长度表示六、遍历数组方法一: 方法二:实例演示:七、数组的初始值总...
    99+
    2024-04-02
  • JAVA注解代码详解一篇就够了
    目录一、java内置注解1、@Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括:1、元注解1.1、@Retention: 定义注解的保留策略1.2、@...
    99+
    2024-04-02
  • FastJson使用详解这一篇就够了
    FastJson文章目录 第一章 FastJson使用详解这一篇就够了 第二章 FastJsonHttpMessageConverter 类的作用与使用详解 第三章 Jackson 使用详解 文章目录 FastJson文章目录前言...
    99+
    2023-08-20
    java 开发语言 json spring boot spring cloud
  • Mybatis配置解析看这一篇就够了
    目录核心配置文件environments元素mappers元素Mapper文件Properties优化typeAliases优化生命周期和作用域总结核心配置文件 mybat...
    99+
    2024-04-02
  • Java学习路线图,看这一篇就够了!
    主要分为三阶段 | 耗废1024根秀发,Java学习路线图来了,整合了自己所学的所有技术整理出来的2022最新版Java学习路线图,适合于初、中级别的Java程序员。可以按照这个序号来学习的,或者把知识过一遍,建议收藏。 阶段一:Java...
    99+
    2023-08-31
    java spring 后端 maven servlet
  • Python:openpyxl这一篇就够了
    各位好,我是轩哥啊哈~ 本文展示如何使用 openpyxl 库在 Python 中使用 Excel 文件。openpyxl 是用于读取和写入 Excel 2010 xlsx / xlsm / xltx / xltm 文件的 Python 库...
    99+
    2023-08-31
    excel python pyqt pygame pip
  • strncpy函数详解看这一篇就够了C语言
    strncpy函数是C语言中的字符串处理函数,用于将一个字符串复制到另一个字符串中,可以指定复制的长度。函数原型:```cchar*...
    99+
    2023-09-09
    C语言
  • Java集合框架最全详解(看这篇就够了)
    Java集合体系框架 Java集合类主要由两个根接口Collection和Map派生出来的。 Collection派生出了三个子接口: 1)List List代表了有序可重复集合,可直接根据元素的索引来访问 2)Set Set代表...
    99+
    2023-09-08
    面试 程序人生 分布式 数据结构 java
  • 什么叫 SSH ?原理详解,看这一篇就够了!
    SSH(Secure Shell,安全外壳)是一种网络安全协议,通过加密和认证机制实现安全的访问和文件传输等业务。传统远程登录或文件传输方式,例如Telnet、FTP,使用明文传输数据,存在很多的安全隐患。随着人们对网络安全的重视,这些方式...
    99+
    2023-08-03
  • Python中计时,看这一篇就够了
    计时对于了解程序的性能是很关键的部分。 本文讨论了Python 2和python 3中计时方法,并完成了一个通用的计时装饰器。 一、python2和python3的通用计时方法 由于python2和3里面的计时函数是不一样的,建议使用ti...
    99+
    2023-01-31
    这一 就够了 Python
  • Python eval() 函数看这一篇就够了
    目录一、语法和参数二、expression参数示例三、globals参数示例四、locals参数示例五、eval函数的危险之处六、eval()函数官方文档附eval()函数常见作用有...
    99+
    2024-04-02
  • Java-lambda表达式入门看这一篇就够了
    目录概述语法函数式接口方法引用构造器引用变量作用域处理lambda表达式 概述 Lambda表达式,也可称为闭包,是JDK8的新特性。Lambda 允许把函数作为一个方法的参数(函数...
    99+
    2024-04-02
  • C++内存管理看这一篇就够了
    目录1 内存分布图2 C语言和C++内存分配实现2.1 C语言实现2.2 C++实现new的原理delete的原理3 C语言和C++内存管理区别4 内存泄漏总结1 内存分布图 注...
    99+
    2024-04-02
  • ES学习看这一篇文章就够了
    第一章 ES简介 第1节 ES介绍 1234 1、Elasticsearch是一个基于Lucene的搜索服务器2、提供了一个分布式的全文搜索引擎,基于restful web接口3、Elasticsearch是用Java语言开发的,基于A...
    99+
    2023-09-01
    elasticsearch 大数据 学习 java
  • C++ Cmake使用详细教程(看这一篇就够了!)
    目录引言一 环境搭建二 简单入门2.1 项目结构2.2 示例源码2.3 运行查看三 编译多个源文件3.1 在同一个目录下有多个源文件3.1.1 简单版本3.1.2 进阶版本3.2 在...
    99+
    2023-03-07
    c++ cmake使用 cmake如何使用 cmake入门
  • Java集合面试题看这篇就够了
    备战实习,会定期的总结常考的面试题,大家一起加油! 🎯 往期文章: 【面试题】计算机网络篇-10道常见面试题p1【面试题】JVM篇-10道常见面试题p1【面试题】Java并发篇-...
    99+
    2023-08-31
    java 面试 经验分享 集合
  • MySQL 8.0 安装详细教程,看这一篇就够了
    同学大家 从今天开始我们就开始了,为期三个月的MySQL,中高级篇幅的学习,欢迎大家持续关注,今天我们首先传授大家 mysql 软件的安装,以及 8.0版本和5.7 版本之间同步教学,(我也是名学生,哪里不理解,欢迎同学们及时与我沟通) ...
    99+
    2023-09-01
    mysql 数据库 python 开发语言
  • python操作Excel神器openpyxl看这一篇就够了
    目录Excel xlsxOpenpyxl 创建新文件Openpyxl 写入单元格Openpyxl 附加值OpenPyXL 读取单元格OpenPyXL 读取多个单元格Openpyxl ...
    99+
    2023-05-14
    openpyxl库是什么 openpyxl库教程 openpyxl库的主要用途
  • Git【入门】这一篇就够了
    版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。除了项目,你可以对任何类型的文件进行版本控制。采用版本控制系统(VCS)是个明智的选择。 有了它就可以将某个文件回溯到之前的状态,甚至将整个项目都回退到过去某个时...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作