对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.下面的对事件的添加和删除做 ...
随机推荐
- C++程序设计方法3:类中的静态成员
在类型前面加static修饰的数据成员,是隶属于类的,成为类的静态数据成员,也称为“类的变量” 静态数据成员被该类的所有对象共享(即所有对象中的这个数据域实际上处于同一个内存位置) 静态数据要在实现文 ...
- 志愿者招募 [NOI2008] [鬼畜网络流]
Description 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完 ...
- Python基础-内置函数、模块、函数、json
内置函数 1.id()返回对象的内存地址: 2. type() 返回对象类型: 3.print()打印输出: 4. input()接受一个标准输入数据,返回为string类型: 5. list() ...
- JWTtoken的原理以及在django中的应用
JWT 在用户注册或者登陆完成之后,记录用户状态,或者为用户创建身份凭证(功能类似于session的作用). 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而 ...
- 【二维树状数组】计数问题 @JSOI2009/upcexam5911
时间限制: 1 Sec 内存限制: 128 MB 题目描述 一个n*m的方格,初始时每个格子有一个整数权值.接下来每次有2种操作: 改变一个格子的权值: 求一个子矩阵中某种特定权值出现的个数. 输入 ...
- 【LCA&倍增】货物运输 @upcexam5909
时间限制: 1 Sec 内存限制: 128 MB 题目描述 在一片苍茫的大海上,有n座岛屿,岛屿与岛屿之间由桥梁连接,所有的岛屿刚好被桥梁连接成一个树形结构,即共n-1架桥梁,且从任何一座岛屿出发都能 ...
- 微信公众号申请+新浪SAE申请
一. 新浪SAE服务申请 1. 注冊地址:http://t.cn/RqMHPto 2. 选择控制台>>云应用SAE 3. 创建新应用 4. 填写域名 5. 代码管理选择SVN 6. 创建版 ...
- AndroidStudio中Handler类的内存溢出风险
package com.test.king.xmlparser; import android.annotation.SuppressLint; import android.app.Activity ...
- jsp执行过程图解
转自:https://blog.csdn.net/y277an/article/details/76561451 一.jsp执行过程图解 用户访问jsp页面时,jsp的处理过程如下图所示: 二.预处理 ...
- 【TCP ZeroWindow】与【TCP window Full】
1.作为接收方,有接收窗口,也就是接收缓冲区,win=xxx 告诉对方,我的接收窗口大小. 2.当我的接收窗口满了,也就是win=0,Wireshark显示[TCP ZeroWindow],这个时候, ...