Java基础-----集合类(四)

文章目录

  • [1. Iterator和ListIterator](#1. Iterator和ListIterator)
    • [1.1 简介](#1.1 简介)
    • [1.2 常用方法](#1.2 常用方法)
  • [2. remove方法](#2. remove方法)
    • [2.1 比较foreach方式和迭代器方式删除元素](#2.1 比较foreach方式和迭代器方式删除元素)
    • [2.2 找原因 -- 迭代器删除操作源码](#2.2 找原因 -- 迭代器删除操作源码)

1. Iterator和ListIterator

1.1 简介

1.Iterator 可以遍历List集合,也可以遍历Set集合; ListIterator只能遍历List集合

2.Iterator 只能单向遍历(向后遍历),ListIterator双向遍历(向前/向后遍历)

3.ListIterator继承Iterator接口,添加新的方法

1.2 常用方法

  • add(E e):将指定的元素插入到集合中,插入位置为迭代器当前位置之前

  • hasNext():正向遍历集合,判断后面是否还有元素,返回boolean类型值

  • next():返回集合中迭代器指向后面位置的元素

  • nextIndex():返回集合中迭代器后面位置元素的索引

  • hasPrevious():反向遍历集合,判断前面是否还有元素,返回boolean类型值

  • previous():返回集合中迭代器指向前面位置的元素

  • previousIndex():返回集合中迭代器前面位置元素的索引

  • set(E e):替换迭代器当前位置的元素

java 复制代码
		List<String> list=new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        for (Iterator<String> iterator= list.iterator();iterator.hasNext();){
            System.out.println(iterator.next());
        }
java 复制代码
		List<String> list=new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
		//正向遍历
        ListIterator<String > iterator=list.listIterator();
        iterator.add("EEE");
        for (String s : list) {
            System.out.println(s);//EEE aa bb cc dd
        }
java 复制代码
		List<String> list=new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");

		ListIterator<String > iterator=list.listIterator();
        iterator.next();
        iterator.add("EEE");
        for (String s : list) {
            System.out.println(s);//aa EEE bb cc dd
        }
        System.out.println("-------------------");
        iterator=list.listIterator();
        for (;iterator.hasNext();){
            System.out.println(iterator.next());
        }
        System.out.println("-------------------");
        iterator=list.listIterator();
        for (;iterator.hasNext();){
            System.out.println(iterator.nextIndex()+"\t"+iterator.next());
        }

运行结果:

java 复制代码
//反向遍历
        ListIterator<String> iterator=list.listIterator(list.size());
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previousIndex()+"\t"+iterator.previous());
        }

运行结果:

java 复制代码
		ListIterator<String> iterator=list.listIterator(list.size());
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previousIndex()+"\t"+iterator.previous());
        }
        iterator.set("GGG");
        System.out.println(list);//[GGG, bb, cc, dd]
----------------------------------------------------------------------------
        ListIterator<String> iterator=list.listIterator(list.size());
        iterator.previous();
        iterator.set("GGG");
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previousIndex()+"\t"+iterator.previous());
        }

        System.out.println(list);//[aa, bb, cc, GGG]

2. remove方法

2.1 比较foreach方式和迭代器方式删除元素

对集合元素进行循环处理增加或删除时,不能使用foreach处理方式,要使用迭代器方式。

  • 使用foreach方法进行删除,报错:java.util.ConcurrentModificationException
java 复制代码
		ArrayList<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");

        for (String s : list) {
            if ("aaa".equals(s)){
                list.remove(s);
            }
        }
        System.out.println(list);
  • 使用迭代器方式删除元素:
java 复制代码
		Iterator<String> iterator=list.iterator();
        while (iterator.hasNext()){
            String x=iterator.next();
            if (x.equals("aaa")){
                iterator.remove();
            }
        }
        System.out.println(list);//[bbb,ccc,ddd]
  • 但是,在foreach对集合中倒数第二个元素进行删除时,不会报错,其他位置的元素都会报错。
java 复制代码
		for (String s : list) {
            if ("ccc".equals(s)){
                list.remove(s);
            }
        }
        System.out.println(list);//[aaa,bbb,ddd]

其中,foreach底层也是通过迭代器实现的。

其实,我们在使用迭代器操作时,有两个步骤:

java 复制代码
iterator.hasNext();//判断是否有下一个元素

item=iterator.next();//有下一个元素的话,取出

2.2 找原因 -- 迭代器删除操作源码

首先,我们进入到Iterator的remove()方法中,找到Itr类,在这个类中我们会看到ArrayList的remove()方法


在remove()方法中,看到里面有个checkForComodification()方法

java 复制代码
		final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

在checkForComodification()方法中,有两个变量:modCount变量和expectedModCount变量,当这两个变量不相同时,就会抛出异常处理(也就是我们在前面遇到的那个异常)

java 复制代码
modCount变量:记录集合对象从new出来到现在被修改的次数

expectedModCount变量:迭代器现在期望这个集合被修改的次数

在上面源码中看到:expectedModCount = modCount;只要保持这两个变量相等,删除操作就没有问题。
所以,迭代器不会报错,使用foreach会报错,原因是:
在迭代器中,对这两个变量进行了同步处理,而foreach没有进行同步处理,导致会出现checkForComodification异常出现。


通过查看源码,有一个hasNext()方法,方法中要比较cursor和size

java 复制代码
		public boolean hasNext() {
            return cursor != size;
        }

cursor是下一个元素的索引值;size是整个集合元素个数

如果两个元素不相等,即有下一个元素,就返回true。

当删除倒数第二个元素时,cursor通过计算之后,得到cursor=size,导致迭代器认为不存在下一个元素,迭代结束。

整体架构如下:

相关推荐
代码不行的搬运工4 分钟前
HTML快速入门-4:HTML <meta> 标签属性详解
java·前端·html
海盗强33 分钟前
Babel、core-js、Loader之间的关系和作用全解析
开发语言·前端·javascript
猿榜编程35 分钟前
python基础-requests结合AI实现自动化数据抓取
开发语言·python·自动化
mask哥1 小时前
详解最新链路追踪skywalking框架介绍、架构、环境本地部署&配置、整合微服务springcloudalibaba 、日志收集、自定义链路追踪、告警等
java·spring cloud·架构·gateway·springboot·skywalking·链路追踪
XU磊2601 小时前
javaWeb开发---前后端开发全景图解(基础梳理 + 技术体系)
java·idea
我最厉害。,。1 小时前
PHP 反序列化&原生类 TIPS&字符串逃逸&CVE 绕过漏洞&属性类型特征
android·开发语言·php
爱编程的鱼1 小时前
C# 类(Class)教程
开发语言·c#
学也不会1 小时前
雪花算法
java·数据库·oracle
2301_817031651 小时前
C语言-- 深入理解指针(4)
c语言·开发语言·算法
晓华-warm1 小时前
国产免费工作流引擎star 5.9k,Warm-Flow版本升级1.7.0(新增大量好用功能)
java·中间件·流程图·开源软件·flowable·工作流·activities