Java中如何优雅地删除List中的元素
在工作中的许多场景下,我们都会使用到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中的元素的更多相关文章
- Java 添加、替换、删除PDF中的图片
概述 本文介绍通过java程序向PDF文档添加图片,以及替换和删除PDF中已有的图片.另外,关于图片的操作还可参考设置PDF 图片背景.设置PDF图片水印.读取PDF中的图片.将PDF保存为图片等文章 ...
- Java 添加、读取、删除Excel中的图表趋势线
本文以Java示例介绍如何在Excel中添加趋势线,以及读取趋势线公式.通过文中的方法可支持添加6种不同类型的趋势线,包括Linear.Exponential.Logarithmic.Moving A ...
- MongoDB中如何优雅地删除大量数据
删除大量数据,无论是在哪种数据库中,都是一个普遍性的需求.除了正常的业务需求,我们需要通过这种方式来为数据库"瘦身". 为什么要"瘦身"呢? 表的数据量到达一定 ...
- oracle中的rowid--伪列-删除表中的重复内容-实用
1.rowid是一个伪列,是用来确保表中行的唯一性,它并不能指示出行的物理位置,但可以用来定位行. 2.rowid是存储在索引中的一组既定的值(当行确定后).我们可以像表中普通的列一样将它选出来. 3 ...
- 如何优雅地删除 Linux 中的垃圾文件
不知道大家是否也跟我一样,是一只要把的自己电脑文件安排的条理有序,把没用的文件会及时删掉的程序猿呢?如果是的话,那么我们可以愉快地探讨下文章的内容.如果不是的话,你也可以留下来凑凑热闹嘛(>-& ...
- Linux中通过命令直接删除文件中最后一行
何谓Sed(Stream EDitor):Sed原为UNIX系统上的非交谈式文字编辑器(non-interactive stream editor).当Sed读入待编辑文件,会依编辑命令来进行文件的编 ...
- 如何删除datatable中的一行数据
在C#中,如果要删除DataTable中的某一行,大约有以下几种办法: 1,使用DataTable.Rows.Remove(DataRow),或者DataTable.Rows.RemoveAt(ind ...
- Java 8 中如何优雅的处理集合
Java 8 中如何优雅的处理集合(Stream API) 在Java中,集合和数组是我们经常会用到的数据结构,需要经常对他们做增.删.改.查.聚合.统计.过滤等操作.相比之下,关系型数据库中也同样有 ...
- [java]删除数组中的某一个元素
package org.company.project.test; import java.util.Arrays; import java.util.Scanner; public class Ar ...
随机推荐
- linux中的标准输出和输入
===============1.有些人经常问我这个问题问题=========== 经常在脚本里面看到这个 2>&1 表示什么意思啊? ==============2.理论 ...
- ubuntu 加扩展网卡遇到网卡无法识别
原创文章,如转载请注明出处 ============================ 今天在安装扩展网卡的时候出现了问题,ubuntu和Centos的网络配置是不一样的. ubuntu的配置: ...
- JDBC的驱动是如何加载的
注:本文出处:http://www.cnblogs.com/jiaoyiping/ 转载请保留出处 JDBC定义了一套接口,数据库产品的提供商会实现这些接口来提供自己的数据库驱动程序,这是个很好的面向 ...
- 转sklearn保存模型
训练好了一个Model 以后总需要保存和再次预测, 所以保存和读取我们的sklearn model也是同样重要的一步. 比如,我们根据房源样本数据训练了一下房价模型,当用户输入自己的房子后,我们就需要 ...
- ArchLinux 添加国内镜像源
$ vim /etc/pacman.d/mirrorlist # 在最前面添加一行,这样就成功添加了网易的源: Server = http://mirrors.163.com/archlinux/$r ...
- 不同修饰符使用细节(java)
常用来修饰类.方法.变量的修饰符如下 public 权限修饰符,公共访问, 类,方法,成员变量 protected 权限修饰符,受保护访问, 方法,成员变量 默认什么也不写 也是一种权限修饰符,默认访 ...
- empty是判断一个变量是否为“空”,而isset 则是判断一个变量是否已经设置
1.echo和print的区别php中echo和print的功能基本相同(输出),但是两者之间还是有细微差别的.echo输出后没有返回值,但print有返回值,当其执行失败时返回flase.因此可以作 ...
- Saltstack实战之无master和多master
如果不想依赖master可以设置为无master vim /etc/salt/minion 就可以通过minion来安装一个salt-master了(下来查资料做,关闭salt-minion进程因为不 ...
- 大数据竞赛平台Kaggle案例实战
Kaggle是由联合创始人.首席执行官安东尼·高德布卢姆(Anthony Goldbloom)2010年在墨尔本创立的,主要为开发商和数据科学家提供举办机器学习竞赛.托管数据库.编写和分享代码的平台. ...
- 最长上升子序列 OpenJ_Bailian - 2757 dp模板
第一种是用以前状态更新当前状态(人人为我) 第二种是用当前状态更新以后状态(我为人人) 都是n^2代码: 对于人人为我的更新方法,可以用数据结构储存“人人”对其进行线性\二分优化. ; int a[m ...