对List遍历过程中添加和删除的思考
对List遍历过程中添加和删除的思考
平时开发过程中,不少开发者都遇到过一个问题:在遍历集合的的过程中,进行add或者remove操作的时候,会出现2类错误,包括:
java.util.ConcurrentModificationException for in遍历过程中add/remove导致的错误
java.lang.IndexOutOfBoundsException 越界错误,for循环的时候删除元素。
最佳实践
add操作:利用原生的for循环。remove操作利用foreach操作。如下所示:
//OK,利用 iterator 和 其remove 方法
@Test
public void testIteratorRemove2() {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if ("3".equals(iterator.next())) {
iterator.remove();
}
}
System.out.println(list);
}
//OK 利用for循环。
@Test
public void testForAdd() {
for (int i = 0, length = list.size(); i < length; i++) {
if (list.get(i).equals("2")) {
list.add("2");
}
}
}
经典错误1
如下代码本意是:通过iterator的方式从头到尾变遍历list中的元素。
@Test
public void testIteratorRemove2() {
while (list.iterator().hasNext()) {
System.out.println(list.iterator().next());
}
}
但是该段代码永远都会输出 list的第一元素,为什么?关键错误在链式写法上:
while (list.iterator().hasNext()) {}
每次循环时候先调用了list.iterator() 在该方法中每次都是重新new了一个新的对象
public Iterator<E> iterator() {
return new Itr();
}
所以每一次都是一个新的遍历对象,所以输出第一个元素。
那么为什么每次都要new一个新的Itr()?我猜想应该是为了并发的读,每次读的都是一份独立的数据,避免多个并发读的时候,出现当前指针问题。
处理办法:将list.iteraotr() 放在外面即可,保证循环中循环的是1个对象。
@Test
public void testIteratorRemove2() {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if ("3".equals(iterator.next())) {
iterator.remove();
}
}
System.out.println(list);
}
经典错误2
// 死循环
@Test
public void testForAdd2() {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals("3")) {
list.add("3");
}
}
}
当if条件满足的时候,该方法永远不会结束,为什么?
对于for循环 for (int i = 0; i < list.size(); i++)有3个部分,第一个部分为初始化,只执行一次。第二个部分每次都会执行,第三个部分也是每次都会执行。
上述问题的第二步会导致无限循环:因为for中每一次循环都会在list添加了一个元素,每次步进为1,内部元素也是每次都加1.
如何处理该问题: list.size()放在第一部分,第一部分只初始化一次。
//OK 利用for循环。
@Test
public void testForAdd() {
for (int i = 0, length = list.size(); i < length; i++) {
if (list.get(i).equals("2")) {
list.add("2");
}
}
}
经典错误3
//java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
@Test
public void testForRemove() {
for (int i = 0, length = list.size(); i < length; i++) {
if (list.get(i).equals("3")) {
list.remove("3");
}
}
}
该错误在list.add("3")的时候就不会发生该错误,具体原因是什么?
Liu CF:转载请保留原文链接,3Q!
对List遍历过程中添加和删除的思考的更多相关文章
- JavaScript向select下拉框中添加和删除元素
JavaScript向select下拉框中添加和删除元素 1.说明 a 利用append()方法向下拉框中添加元素 b 利用remove()方法移除下拉框中最后一个元素 2.设计源码 < ...
- 怎样Zbrush 4R7中添加和删除SubTool
添加或删除SubTool在ZBrush®软件中是非常简单易操作的,通常在用SubTool面板已经给我们提供了相应的命令来对其进行操作,它能够将一个或多个格式为ZTL的文件同时添加进SubTool里. ...
- MySql中添加用户/删除用户
MySql中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束): 1.新建用户 登录MYSQL: @>mysql -u root -p @>密码 ...
- MySQL中添加、删除约束
MySQL中6种常见的约束:主键约束(primary key).外键约束(foreign key).非空约束(not null).唯一性约束(unique).默认值约束(defualt).自增约束(a ...
- vector容器中添加和删除元素
添加元素: 方法一: insert() 插入元素到Vector中 iterator insert( iterator loc, const TYPE &val ); //在指定位置loc前插入 ...
- vue中添加与删除,关键字搜索
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 在Ubuntu中添加和删除PPA的软件源
PPA,英文全称为 Personal Package Archives,即个人软件包档案.是 Ubuntu Launchpad 网站提供的一项源服务,允许个人用户上传软件源代码,通过 Launchpa ...
- 利用JS实现在li中添加或删除class属性
$( function() { $("#test li").click(function(){ $("#test li").removeClass(" ...
- 原生js事件的添加和删除
在IE浏览器中添加或删除事件用attachEvent.detachEvent.在其他标准浏览器中则用addEventListener.removeEventListener.下面的对事件的添加和删除做 ...
随机推荐
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...
- Yii2 DetailView小部件
DetailView小部件 Yii 提供了一套数据库小部件 widgets,这些小部件可以用于显示数据 DetailView 小部件用于显示一条记录数据 ListView 和 GridView 可以用 ...
- Mac redis入门
Mac redis入门 一.Redis简介 Redis是开源的key-value数据库,运行在内存中,但可以把数据持久化存到磁盘.Redis具有极高的性能,也为各种语言提供了丰富的接口,因此有着广泛的 ...
- JS_高程6.面向对象的程序设计(2)创建对象_2 构造函数也是一般函数
1.构造函数也是一般函数,以下创建一个构造函数. var Person=function(name,age,job){ this.name=name; this.age=age; this.job=j ...
- javascript对样式的操作
js可实现用户对页面中的选择条件改变页面中的样式,页面样式可以通过style修饰,也可以通过css修饰,先来看一下js改变style样式,代码如下: 案例一: <!DOCTYPE html> ...
- 【数论&想法题】小C的问题 @"科林明伦杯"哈尔滨理工大学第八届程序设计竞赛
Time Limit: 1000 MS Memory Limit: 256000 K Description 小C是一个可爱的女孩,她特别喜欢世界上最稳定的图形:三角形.有一天她得到了n根木棍,她把这 ...
- C# RabbitMQ延迟队列功能实战项目演练
一.需求背景 当用户在商城上进行下单支付,我们假设如果8小时没有进行支付,那么就后台自动对该笔交易的状态修改为订单关闭取消,同时给用户发送一份邮件提醒.那么我们应用程序如何实现这样的需求场景呢?在之前 ...
- Exchange - Add Owner of Distribution Group
User Interface: Open Exchange Management Console. Expand Microsoft Exchange On-Premises, then right ...
- [rtsp]海康IPC监控摄像头远程外网监控配置(DDNS)
本来这个DDNS服务正是我想要的,但是配置了之后海康提示不再提供这个服务了,以后统一使用萤石云了,看来有必要去学习下萤石开放平台的api,看都提供哪些服务. 海康威视网络摄像机出厂的默认IP地 ...
- Spark2.2(三十九):如何根据appName监控spark任务,当任务不存在则启动(任务存在当超过多久没有活动状态则kill,等待下次启动)
业务需求 实现一个根据spark任务的appName来监控任务是否存在,及任务是否卡死的监控. 1)给定一个appName,根据appName从yarn application -list中验证任务是 ...