java 如何实现正确的删除集合中的元素

 更新时间:2020年09月28日 10:01:03   作者:带你装逼带你飞的程序猿  
这篇文章主要介绍了java 如何实现正确的删除集合中的元素,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

在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循环是编译器认可而并不是虚拟机认可。编译器最终会把新循环改编为迭代器循环)

以上这篇java 如何实现正确的删除集合中的元素就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java并发编程之Fork/Join框架详解

    Java并发编程之Fork/Join框架详解

    这篇文章主要介绍了Java并发编程之Fork/Join框架详解,Fork/Join框架是Java7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架,需要的朋友可以参考下
    2023-12-12
  • Spring Cloud Ribbon的使用原理解析

    Spring Cloud Ribbon的使用原理解析

    现在Java非常流行微服务,也就是所谓的面向服务开发,将一个项目拆分成了多个项目,其优点有很多,其中一个优点就是:将服务拆分成一个一个微服务后,我们很容易的来针对性的进行集群部署,这篇文章主要介绍了Spring Cloud Ribbon的使用详解,需要的朋友可以参考下
    2022-07-07
  • Java字符流和字节流对文件操作的区别

    Java字符流和字节流对文件操作的区别

    本篇文章主要介绍了Java的IO流分为字符流(Reader,Writer)和字节流(InputStream,OutputStream),字节流顾名思义字节流就是将文件的内容读取到字节数组,对初学者很有用,有需要的朋友可以了解一下。
    2016-10-10
  • mybatis-plus的SafetyEncryptProcessor安全加密处理示例解析

    mybatis-plus的SafetyEncryptProcessor安全加密处理示例解析

    这篇文章主要为大家介绍了mybatis-plus的SafetyEncryptProcessor安全加密处理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 详解Java是如何通过接口来创建代理并进行http请求

    详解Java是如何通过接口来创建代理并进行http请求

    今天给大家带来的知识是关于Java的,文章围绕Java是如何通过接口来创建代理并进行http请求展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • SpringBoot中创建bean的7种方式总结

    SpringBoot中创建bean的7种方式总结

    Spring是一款广泛应用于企业级应用程序开发的Java框架,其 IOC 和 DI 特性可以有效地管理应用程序中的对象,提高了应用程序的可维护性和可扩展性,那你知道spring有哪些方式将bean放入容器嘛,今天就给大家总结一下
    2023-07-07
  • springboot2.0以上调度器配置线程池的实现

    springboot2.0以上调度器配置线程池的实现

    这篇文章主要介绍了springboot2.0以上调度器配置线程池的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 用Java8 stream处理数据

    用Java8 stream处理数据

    这篇文章主要介绍了用Java8 stream处理数据,Java 8 API的设计者重新提出了一个新的抽象称为流Stream,可以让我们以一种声明的方式处理数据,此外,数据流可以充分利用多核架构而无需编写多线程的一行代码,下面我们一起来看看文章详细介绍
    2021-11-11
  • java实现多图片上传功能

    java实现多图片上传功能

    这篇文章主要为大家详细介绍了java多图片同步上传功能的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • mybatis mapper.xml中如何根据数据库类型选择对应SQL语句

    mybatis mapper.xml中如何根据数据库类型选择对应SQL语句

    这篇文章主要介绍了mybatis mapper.xml中如何根据数据库类型选择对应SQL语句,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01

最新评论