java 如何实现正确的删除集合中的元素
作者:带你装逼带你飞的程序猿 发布时间:2022-08-03 17:44:31
在java中如果我们需要遍历集合并删除其中的某些元素时,例如对于List来说,我们有三种办法。
1. 普通的for循环遍历并删除
public void forRemove(List<T> list, T obj){
for(int i = 0;i < list.size(); i++){
if (obj == list.get(i))
{
list.remove(obj);
}
}
}
main中调用
<pre name="code" class="java">
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("2");
list.add("3");
re.forRemove(list,"2");
System.out.println(list.toString());
程序输出[1,2,3]
这是因为,删除时改变了list的长度。删除第一个2后,长度变为了3,这时list.get(2)为3,不再是2了,不能删除第2个2
2. forEach循环删除
public void forEachRemove(List<T> list, T obj){
for(T item : list){
if (item.equals(obj)) {
list.remove(obj);
}
}
}
main方法中:
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("2");
list.add("3");
//re.forRemove(list,"2");
re.forEachRemove(list,"2");
System.out.println(list.toString());
程序输出:
从运行结果看到程序抛ConcurrentModificationException。
JDK的API中对该异常描述道:
public class ConcurrentModificationException extends RuntimeException当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。
Java中的For each实际上使用的是iterator进行处理的。而iterator是不允许集合在iterator使用期间删除的。所以导致了iterator抛出了ConcurrentModificationException 。
3. Iterator 迭代器删除(推荐)
public void iteratorRemove(List<T> list, T obj){
Iterator<T> it = list.iterator();
while(it.hasNext()){
T item = it.next();
if (item.equals(obj))
{
it.remove();//remove the current item
}
}
}
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("2");
list.add("3");
//re.forRemove(list,"2");
//re.forEachRemove(list,"2");
re.iteratorRemove(list,"2");
System.out.println(list.toString());
程序输出:
可以看到这才是真正的删除了我们想删除的元素。但是需要注意以下两点
对Iterator的remove()方法调用必须在Iterator的next()方法之后。
调用next()方法后只能执行一次remove()方法
综上,对于集合的删除操作,特别是List,需要使用迭代器来操作。
补充知识:java中的Collection集合的存入与删除
在java的集合中存储的都是引用类型元素,而且集合只保存每个元素对象的引用,而并非将元素对象本身存入集合。
Collection集合中的remove方法,对于重复元素而言只删除一个
在遍历集合时,若想删除集合里面的元素,只能通过迭代器的删除方法去删除,不能使用集合本身的方法。(这也是为什么在增强for循环中不能使用集合的方法删除元素的原因,因为增强for循环是编译器认可而并不是虚拟机认可。编译器最终会把新循环改编为迭代器循环)
来源:https://blog.csdn.net/qiyei2009/article/details/51945883


猜你喜欢
- 使用命令行的方式管理服务器镜像及容器是运维人员最常用的方式,但是有的时候我们不得不远程操作docker或者是面向对docker并不熟悉的技术
- 熟悉Android的朋友们都知道,不管是微博客户端还是新闻客户端,都离不开列表组件,可以说列表组件是Android数据展现方面最
- 问题为了避免空指针调用,我们经常会看到这样的语句:if (someobject != null) { someob
- Java 的表格表格是一个由多行,多列组成的二维显示区。Swing的JTable以及相关类提供了对这种表格的支持,程序既可以使用简单的代码创
- 工厂接口定义/// <summary> /// 工厂接口定义 &nbs
- 一、显示信息对话框:使用“JOptionPane.showMessageDialog”显示:图标对话框类型语法显示错误类型对话框showMe
- 安卓的开发从布局开始。安卓的界面编写也是使用xml进行布局的,一般如果熟悉了html界面的布局,那么很容易就能够理解安卓有关的布局了,这里介
- 本文介绍了SharedPreferences保存应用程序数据的具体步骤,供大家参考,具体内容如下1、SharedPreferences的简单
- jdk中自带了很多工具可以用于性能分析,位于jdk的bin目录下,jvisualvm工具可以以图形化的方式更加直观的监控本地以及远程的jav
- 前言最近遇到想要实现三指滑动监听的需求,实现代码不方便贴出来,但是思路还是可以记录一下。Muilti-touch 双指缩放探索首先要实现On
- 1、 在Java1.7之前,我们需要通过下面这种方法, 在finally中释放资源,这种方法有点繁琐。 BufferedReader br
- 在Spring Boot集成Mybatis的项目中,如果出现SQL语句执行问题,我们需要进行排查。此时就需要打印对应的SQL语句,那么该如何
- 前言平时日常开发用得最多是Http通讯,接口调试也比较简单的,也有比较强大的框架支持(OkHttp)。个人平时用到socket通讯的地方是A
- 今天给大家带来的是一个 SpringBoot导入导出数据首先我们先创建项目 注意:创建SpringBoot项目时一定要联网不然会报错项目创建
- 前言本文主要介绍的是关于C#中LINQ多条件JOIN时为什么可以使用匿名类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细
- 方法一:Handler+Threadpackage com.xunfang.handerDemo; import android.app.A
- SQLite毕竟是在手机上的数据库,开发者想在电脑上看还是比较烦恼,但相信大多数对navicat有所耳闻,我用的navicat 12就觉得数
- 公司编辑妹子需要爬取网页内容,叫我帮忙做了一简单的爬取工具这是爬取网页内容,像是这对大家来说都是不难得,但是在这里有一些小改动,代码献上,大
- 八皇后问题(N皇后问题)的回溯法求解一、问题描述在一个国际象棋棋盘上放置八个皇后,使得任何两个皇后之间不相互攻击,求出所有的布棋方法,并推广
- @RequestBody配合@Valid校验入参参数自定义一个Controllerimport com.example.demo.pojo.