进阶JAVA篇- Collcetions 工具类与集合的并发修改异常问题

news2024/12/23 22:43:52

目录

        1.0 集合的并发修改问题

                1.1 如何解决集合的并发修改问题

        2.0 Collcetions 工具类的说明


        1.0 集合的并发修改问题

        我们可以简单的认为,就是使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。

代码如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Abnormal {
    public static void main(String[] args) {

        //创建对象,再添加数据
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("陈七");
        list.add("李麻子");
        list.add("李四");
        list.add("王五");
        //利用迭代器进行遍历,先创建迭代器
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String a = iterator.next();
            if (a.contains("李")){
                list.remove(a);
            }
        }
        System.out.println(list);
    }
}

运行结果如下:

       

        像以上情况,一边遍历的时候去删除数据,直接会报错,原因是因为集合是一个可变的容器,每删一个数据,容器的大小都会改变,那么数据存放的位置也会相应的改变。迭代器遍历可能不好理解,我们就换成普通的 for 循环,但是两者的出现的 Bug 是一样的。

代码如下:

import java.util.ArrayList;
import java.util.List;

public class Text_For {
    public static void main(String[] args) {
        //创建对象,再添加数据
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("陈七");
        list.add("李麻子");
        list.add("李四");
        list.add("王五");

        for (int i = 0; i < list.size(); i++) {
            String a = list.get(i);
            if (a.contains("李")){
                list.remove(a);
            }
        }
        System.out.println(list);
    }
}

运行结果如下:

        发现用 for 循环竟然不报错,原因可能是没有用迭代器遍历严谨吧,以上的两种代码的效果都是一样的,会出现 Bug ,就是本来要删除带 ”李“ 的名字,但是发现名字还有一个”李四“,没有被删除,那是什么原因呢?

        

        直接会把 ”李四“ 忽略掉,这就是这出现 Bug 的地方。

                1.1 如何解决集合的并发修改问题

        对于用普通的 for 循环来遍历的代码来说可以有两种方法;第一个方法就是每一次删除数据的时候,都要进行 i--; 第二方法就是从尾开始遍历。

代码如下:

第一种方法

import java.util.ArrayList;
import java.util.List;

public class Text_For {
    public static void main(String[] args) {
        //创建对象,再添加数据
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("陈七");
        list.add("李麻子");
        list.add("李四");
        list.add("王五");

        for (int i = 0; i < list.size(); i++) {
            String a = list.get(i);
            if (a.contains("李")){
                list.remove(a);
                i--;
            }
        }
        System.out.println(list);
    }
}

运行结果如下:

        成功把”李四“也删除掉了。

第二种方法

import java.util.ArrayList;
import java.util.List;

public class Text_For {

    public static void main(String[] args) {
        //创建对象,再添加数据
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("陈七");
        list.add("李麻子");
        list.add("李四");
        list.add("王五");

        for (int i = list.size() - 1; i >= 0; i--) {
            String a = list.get(i);
            if (a.contains("李")){
                list.remove(a);
            }
        }
        System.out.println(list);
    }
}

运行结果如下:

        一样也可以把”李四“删除掉。

        对于用迭代器来遍历的代码来说,只能把集合对象.remove(String str) 换成迭代器对象.remove()

代码如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Abnormal {
    public static void main(String[] args) {

        //创建对象,再添加数据
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("陈七");
        list.add("李麻子");
        list.add("李四");
        list.add("王五");
        //利用迭代器进行遍历,先创建迭代器
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String a = iterator.next();
            if (a.contains("李")){
                iterator.remove();
            }
        }
        System.out.println(list);
    }
}

运行结果如下:

        也是可以的。

        对于增强 for 循环还有利用 Lambda 表达式的循环都不可以用来一边遍历集合,一边删除数据,无法解决集合的并发修改异常。

        2.0 Collcetions 工具类的说明

        是一个用来操作集合的工具类。

以代码为例来介绍具体的静态方法:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Text_Collections {
    public static void main(String[] args) {
        String s1 = "李四";
        String s2 = "张三";
        String s3 = "王五";
        String s4 = "张麻子";
        List<String> list = new ArrayList<>();

        //1. addAll() 为集合批量添加数据
        Collections.addAll(list,s1,s2,s3,s4);
        System.out.println(list);
        //输出结果为:[李四, 张三, 王五, 张麻子]

        //2. shuffle() 打乱list集合中的元素顺序
        Collections.shuffle(list);
        System.out.println(list);
        //输出结果为:[王五, 张麻子, 李四, 张三]

        //3. sort() 对list集合的元素进行升序排序
        Collections.sort(list);
        System.out.println(list);
        //输出结果为:[张三, 张麻子, 李四, 王五]

    }
}

运行结果如下:

         补充第三种方法,如果对自定的对象进行排序的话,默认的 sort 是会报错的,所以得自定义比较,创建一个比较器。

代码如下:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Text_Collections {
    public static void main(String[] args) {
        Student s1 = new Student("张三",19);
        Student s2 = new Student("李四",33);
        Student s3 = new Student("王五",21);

        List<Student> list = new ArrayList<>();
        Collections.addAll(list,s1,s2,s3);
        //自定义,根据年龄进行排序
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge()- o2.getAge();
            }
        });
        System.out.println(list);
    }
}

运行结果如下:

 



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1119166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux性能分析(五)CPU篇(一)基础

一 CPU篇 遗留&#xff1a; 负载与cpu关系、负载与线程的关系? ① CPU 相关概念 1、physical 物理CPU个数 --> 一般一个实体 2、cpu 核数 3、逻辑CPU个数 逻辑核 4、超线程 super thread 技术 5、各种cpu的计算方式物理 physical CPU的个数&#xff1a; physical id逻…

【Javascript】创建对象的几种方式

通过字面量创建对象 通过构造函数创建对象 Object()-------------构造函数 通过构造函数来实例化对象 给person注入属性 Factory工厂 this指向的是对象的本身使⽤new 实例化⼀个对象&#xff0c;就像⼯⼚⼀样

5G学习笔记之5G频谱

参考&#xff1a;《5G NR通信标准》1. 5G频谱 1G和2G移动业务的频段主要在800MHz~900MHz&#xff0c;存在少数在更高或者更低频段&#xff1b;3G和4G的频段主要在450MHz ~ 6GHz&#xff1b;5G主要是410MHz ~ 6GHz&#xff0c;以及24GHz ~ 52GHz。 5G频谱跨度较大&#xff0c;可…

TCP为什么需要三次握手和四次挥手?

一、三次握手 三次握手&#xff08;Three-way Handshake&#xff09;其实就是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包 主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备 过程如下&#xff…

laravel 中 npm run 同时执行多个命令

在使用laravel 启动项目时 经常需要同时运行两个命令。 1.前端既是 npm run dev 2.后端php则是 php artisan serve 可以安装 使用 concurrently 进行并行启动 concurrently - npm npm install concurrently --save 之后修改 package.json 在 scripts 中增加 &#xff08;多条…

shell算术运算符

文章目录 算术运算符&#xff1a;算术运算扩展算术运算指令expr算术运算指令let自增自减运算符 算术运算符&#xff1a; 加法 - 减法 * 乘法 / 除法 % 取余 ** 幂运算算术运算扩展 算术运算扩展的运算数只能是整数 [rootlocalhost tmp]# num1$[41] [rootlocalhost tmp]# echo …

软件测试肖sir__python之ui自动化测试框架unittest

ui自动化测试框架unittest 一、自动化框架 1、自动化框架类型 &#xff08;1&#xff09;unittest框架 &#xff08;python中自带框架&#xff09; &#xff08;2&#xff09;pytest框架 &#xff08;第三方库&#xff09; &#xff08;3&#xff09;po框架 &#xff08;分层思…

10.一篇文章带你理解及使用CSS(前端邪术-化妆术)

文章目录 1. CSS 是什么2.基本语法规范3.引入方式3.1内部样式表3.2行内样式表3.3外部样式 4.代码风格4.1样式格式4.2样式大小写4.3空格规范 5.选择器5.1选择器的功能5.2选择器的种类5.3基础选择器5.3.1标签选择器5.3.2类选择器5.3.3 id 选择器5.3.4通配符选择器5.3.5基础选择器…

pytest自动化测试数据驱动yaml/excel/csv/json

这篇文章主要为大家介绍了pytest自动化测试数据驱动yaml/excel/csv/json的示例详解&#xff0c;有需要的朋友可以借鉴参考下。− 数据驱动 数据的改变从而驱动自动化测试用例的执行&#xff0c;最终引起测试结果的改变。简单说就是参数化的应用。 测试驱动在自动化测试中的应…

初始C++入门(2)

缺省参数 缺省参数是 声明或定义函数时 为函数的 参数指定一个缺省值 。在调用该函数时&#xff0c;如果没有指定实 参则采用该形参的缺省值&#xff0c;否则使用指定的实参。 有句俗话叫&#xff0c;做人不能像缺省函数。 #include<iostream> using namespace std;void…

C# winform如何实现数据的保存和读取

在c#winform中我们在写程序时&#xff0c;经常需要进行数据处理&#xff0c;那么数据如何保存和读取&#xff08;下面我们通过序列化和反序列化的方式来实现&#xff09; 第一步: 我们建立一个winform窗体 第二步: 构建一个外部实体类&#xff08;Student类&#xff09; 第…

再谈String

文章目录 一、字符串常量池1.1 创建对象的思考1.2 字符串常量池(StringTable)1.3 再谈String 对象创建 一、字符串常量池 1.1 创建对象的思考 下面创建String对象的方式相同吗&#xff1f; public static void main(String[] args) {String s1 "hello";String s2…

Java日志系统之Slf4j

目录 Slf4j Slf4j的简单使用 Slf4j的日志绑定流程 Slf4j桥接器 Slf4j Slf4j又称简单日志门面&#xff0c;Slf4j主要是为了给Java日志访问提供一套标准&#xff0c;规范的API框架&#xff0c;其主要意义在于提供接口&#xff0c;具体的实现可以交由其他的日志框架。 Slf4j…

概念解析 | 心脏电活动和机械活动之间的关系

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:心脏电活动和机械活动之间的关系。 心跳的交响乐:心脏电活动与机械活动之间的关联 一、背景介绍 心脏通过不断跳动将血液输送到我们身体的每一个角落。而这个跳动过程,是…

【Godot】【BUG】4.x NavigationAgent 导航不生效

4.2.beta2 试了半天才发现原来默认只对第一个有导航的 TileMap 的第 1 层 生效&#xff0c;而我设置的导航层不是第一层&#xff0c;然后我新建了一个 TileMap 将导航的瓦片设置到这个 TileMap 上了&#xff0c;如图 这样就解决了问题&#xff0c;不用再修改默认设置的东西了&a…

超详细 | 差分进化算法原理及其实现(Matlab/Python)

差分进化(Differential Evolution&#xff0c;DE)算法是由美国学者Storn和 Price在1995年为求解Chebyshev多项式拟合问题而提出的。算法主要通过基于差分形式的变异操作和基于概率选择的交叉操作进行优化搜索&#xff0c;虽然其操作名称和遗传算法相同&#xff0c;但实现方法有…

英语——词根篇——单词——f

文章目录 31 . factfactdo,make做&#xff0c;作&#xff08;fact也作fac&#xff09; 32.ferferbring&#xff0c;carry带&#xff0c;拿 33 . florflorflower花&#xff08;flow也作flour&#xff09; 34 . flufluflow流 35 . fusfaus pour灌&#xff0c;流&#xff0c;倾泻 …

IOS屏幕旋转监听

1.设计窗口,添加三个按钮 2.添加事件连接 3.按钮点击事件实现 先添加三个IBAction 实现IBAction 使用旋转立刻生效 -(IBAction)btnFixPortrait:(id)sender{//访问应用程序委托成员_app.mask UIInterfaceOrientationMaskPortrait;//设置窗口旋转属性[self setNeedsUpdateOf…

有效管理token,充分发挥ChatGPT的能力

目录 给提供了 Token 的计算工具,来理解一下Token的计算方式,网址如下: 窗口如下: 实际消耗 Token 数量为 59个,换算之后为2.1-2.2的比例,即一个汉字消耗2.12.2个Token, 再测一下英文的Token消耗,包含空格在内,一共52个英文字母,消耗Token 13个,正好对应13个单词,…

Linux中shell外壳,用户权限,文件权限

Linux 权限 1.shell外壳1.1 shell外壳的定义1.2 shell外壳的作用1.3 shell的原理 2.Linux用户权限2.1创建普通用户2.2 用户之间的切换2.3 sudo指令 3.Linux文件权限3.1文件访问者的分类&#xff08;人&#xff09;3.2 文件文件类型和访问权限&#xff08;事物属性&#xff09;3…