在工作中的许多场景下,我们都会使用到List这个数据结构,那么同样的有很多场景下需要删除List中的某一个元素或某几个元素,那么我们该如何正确无误地删除List中的元素的,今天我来教大家三种方式。

前提知识准备

for循环的执行顺序

这里借用百度百科的一张图,简明扼要的介绍一下。

Iterator迭代器介绍

迭代器:迭代其实我们可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类,它是一个很典型的设计模式。Iterator 模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向每次遍历前都需要知道要遍历集合的内部结构。

// 遍历list
List list = new ArrayList();
list.add(1);
list.add(2);
for (int i = 0; i < list.size(); i++) {
Object object = list.get(i);
// do something
} // 遍历map
Map<String,String> map = new HashMap<>();
map.put("1","first");
map.put("2","second");
for (Map.Entry<String,String> entry : map.entrySet()){
String key = entry.getKey();
String value = entry.getValue();
// do something
}

对于这两种方式,我们总是都事先知道集合的内部结构,访问代码和集合本身是紧密耦合的,无法将访问逻辑从集合类和遍历方法中分离出来。同时每一种集合对应一种遍历方法,代码无法复用。
为了解决以上问题, Iterator 模式腾空出世,它总是用同一种逻辑来遍历集合。使得需要遍历集合的人,在遍历的时候不需要了解集合的内部结构,所有的内部状态都由 Iterator 来维护。遍历集合的方法不直接和集合类打交道,它总是控制 Iterator,向它发送”向前”,”向后”,”取当前元素”的命令,就可以间接遍历整个集合。

错误:for循环顺序遍历

直接使用简单for循环,以for (int i = 0; i < list.size(); i++) 进行遍历,这种方式可能会在遍历的过程中漏掉部分元素,从而出现少删的情况。

/**
* 通过简单的遍历方式,在遍历的过程中有可能会漏掉元素
* 取第二个元素i=1时,满足条件被删掉,原有的数组的第三个元素,变成了新数组的第二个元素
* i++后i=2,但i=2指向的是新数组中的第三个元素,那么原数组中的第三个元素就被漏掉了
*
* @param list
* @param element
* @return
*/
public static List forRemove(List list, Object element) {
for (int i = 0; i < list.size(); i++) {
if (element.equals(list.get(i))) {
list.remove(i);
}
}
return list;
}

错误:增强for循环,删除后不退出

使用增强for循环是,如果删除后继续向下循环则会报java.util.ConcurrentModificationException

/**
* 使用增强for循环是,如果删除后继续向下循环则会报
* java.util.ConcurrentModificationException
*
* @param list
* @param element
* @return
*/
public static List forceForRemove(List list, Object element) {
for (Object item : list) {
if (item.equals(element)) {
list.remove(item);
}
}
return list;
}

异常如下:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at com.lingyejun.leetcode.RemoveListElement.forceForRemove(RemoveListElement.java:57)
at com.lingyejun.leetcode.RemoveListElement.main(RemoveListElement.java:112)

正确:逆向循环遍历

我们使用逆向遍历的方式可以得到正确的结果

/**
* 逆向循环,是正确的
* 1-->2-->3-->4
* 逆向循环时,倒数第一个元素满足条件被删除时,i--后,原数组的倒数第二个变成了新数组的倒数第一个元素
* i = size-2指向新数组的最后一个元素,没有漏掉。
* 同理倒数第二个元素满足条件被删除时,i--后,原数组的倒数第三个变成了新数组的倒数第二个元素
* i= size-3指向新数组的倒数第二个元素,也没有漏掉
*
* @param list
* @param element
* @return
*/
public static List reverseorRemove(List list, Object element) {
for (int i = list.size() - 1; i >= 0; i--) {
if (element.equals(list.get(i))) {
list.remove(i);
}
}
return list;
}

正确但不优雅:增强for循环删除元素后break

使用增强for循环,删除元素后,立即跳出,则正常退出,但缺点是不能向后继续循环了。  

/**
* 删除元素后,立即跳出,则正常退出,但不能向后继续循环了
*
* @param list
* @param element
* @return
*/
public static List forceForRemove1(List list, Object element) {
for (Object item : list) {
if (item.equals(element)) {
// 删除后立马终端循环,会正常跳出,但代价是不能继续向后循环了
list.remove(item);
break;
}
}
return list;
}

优雅删除:使用Iterator迭代器

使用迭代器可,正确无误的删除,代码简洁优雅,推荐使用!

/**
* 使用迭代器可,正确无误的删除
*
* @param list
* @param element
* @return
*/
public static List iteratorRemove(List list, Object element) {
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object cur = iterator.next();
if (cur.equals(element)) {
// 注意!!!这里时Iterator.remove()!!!而不是list.remove()!!!
iterator.remove();
}
}
return list;
}

参考文章:

https://jingyan.baidu.com/article/7f766dafaa6ee04101e1d0e6.html

http://wiki.jikexueyuan.com/project/java-enhancement/java-thirty.html

Java中如何优雅地删除List中的元素的更多相关文章

  1. Java 添加、替换、删除PDF中的图片

    概述 本文介绍通过java程序向PDF文档添加图片,以及替换和删除PDF中已有的图片.另外,关于图片的操作还可参考设置PDF 图片背景.设置PDF图片水印.读取PDF中的图片.将PDF保存为图片等文章 ...

  2. Java 添加、读取、删除Excel中的图表趋势线

    本文以Java示例介绍如何在Excel中添加趋势线,以及读取趋势线公式.通过文中的方法可支持添加6种不同类型的趋势线,包括Linear.Exponential.Logarithmic.Moving A ...

  3. MongoDB中如何优雅地删除大量数据

    删除大量数据,无论是在哪种数据库中,都是一个普遍性的需求.除了正常的业务需求,我们需要通过这种方式来为数据库"瘦身". 为什么要"瘦身"呢? 表的数据量到达一定 ...

  4. oracle中的rowid--伪列-删除表中的重复内容-实用

    1.rowid是一个伪列,是用来确保表中行的唯一性,它并不能指示出行的物理位置,但可以用来定位行. 2.rowid是存储在索引中的一组既定的值(当行确定后).我们可以像表中普通的列一样将它选出来. 3 ...

  5. 如何优雅地删除 Linux 中的垃圾文件

    不知道大家是否也跟我一样,是一只要把的自己电脑文件安排的条理有序,把没用的文件会及时删掉的程序猿呢?如果是的话,那么我们可以愉快地探讨下文章的内容.如果不是的话,你也可以留下来凑凑热闹嘛(>-& ...

  6. Linux中通过命令直接删除文件中最后一行

    何谓Sed(Stream EDitor):Sed原为UNIX系统上的非交谈式文字编辑器(non-interactive stream editor).当Sed读入待编辑文件,会依编辑命令来进行文件的编 ...

  7. 如何删除datatable中的一行数据

    在C#中,如果要删除DataTable中的某一行,大约有以下几种办法: 1,使用DataTable.Rows.Remove(DataRow),或者DataTable.Rows.RemoveAt(ind ...

  8. Java 8 中如何优雅的处理集合

    Java 8 中如何优雅的处理集合(Stream API) 在Java中,集合和数组是我们经常会用到的数据结构,需要经常对他们做增.删.改.查.聚合.统计.过滤等操作.相比之下,关系型数据库中也同样有 ...

  9. [java]删除数组中的某一个元素

    package org.company.project.test; import java.util.Arrays; import java.util.Scanner; public class Ar ...

随机推荐

  1. Django---项目如何创建

    首先是安装好Django,找到 Scripts 目录配置环境变量: 只要添加到环境变量,在任何目录执行 django-admin startproject mysite 就可以创建 Django 程序 ...

  2. POJ-1322 Chocolate(概率DP)

    Chocolate Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9279 Accepted: 2417 Special Jud ...

  3. POJ-1887 Testing the CATCHER(dp,最长下降子序列)

    Testing the CATCHER Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 16515 Accepted: 6082 ...

  4. PAT甲1077 Kuchiguse【字符串】【暴力】【Hash】【二分】

    1077 Kuchiguse (20 分) The Japanese language is notorious for its sentence ending particles. Personal ...

  5. oracle union 用法

    [sql] view plaincopyprint?众所周知的几个结果集集合操作命令,今天详细地测试了一下,发现一些问题,记录备考. 假设我们有一个表Student,包括以下字段与数据: drop t ...

  6. Oracle管理监控之如何对数据库进行监控检查

    oracle自动工作负载库(AWR):采集与性能相关的统计数据,并从统计的数据中导出性能量度,以跟踪数据库潜在的问题. 如何生成oracle数据库的自动负载库报告. 手工生成一份oracle数据库的快 ...

  7. MySQL InnoDB的存储结构总结

    从物理意义上来讲,InnoDB表由共享表空间.日志文件组(redo文件组).表结构定义文件组成.若将innodb_file_per_table设置为on,则系统将为每一个表单独的生成一个table_n ...

  8. element 表格元素 超链接

    1.在循环体中的事件绑定 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...

  9. iOS-Foundation框架—结构体(转载)

    一.基本知识 Foundation—基础框架.框架中包含了很多开发中常用的数据类型,如结构体,枚举,类等,是其他ios框架的基础. 如果要想使用foundation框架中的数据类型,那么包含它的主头文 ...

  10. 5839Special Tetrahedron---hdu5839(计算几何,求特殊四面体个数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5839 给你n个三维的点,然后求这n各点可以构成多少个特殊四面体,特殊四面体满足一下两点: 1.至少有四 ...