【Java】集合(List、Set)遍历、判断、删除元素时的小陷阱
开发中,常有场景:遍历集合,依次判断是否符合条件,如符合条件则删除当前元素。
不知不觉中,有些陷阱,不知你有没有犯。
一、漏网之鱼-for循环递增下标方式遍历集合,并删除元素
如果你用for循环递增下标方式遍历集合,在遍历过程中删除元素,你可能会遗漏了某些元素。说那么说可能也说不清楚,看以下示例:
import java.util.ArrayList;
import java.util.List; public class ListTest_Unwork { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println("Original list : " + list); String temp = null;
for (int i = 0; i < list.size(); i++) {
temp = list.get(i); System.out.println("Check for " + temp);
if ("3".equals(temp)) {
list.remove(temp);
}
}
System.out.println("Removed list : " + list);
} }
日志打印:
Original list : [1, 2, 3, 4, 5]
Check for 1
Check for 2
Check for 3
Check for 5
Removed list : [1, 2, 4, 5]
如日志所见,其中值为4的元素并未经过判断,漏网之鱼。
解决方法为以下两个(但一般不建议我们在遍历中用不是遍历本身的函数删除元素,见下节关于“ConcurrentModificationException”的内容):
1、对于此情况,我一般都从后面开始遍历,以避免问题:
import java.util.ArrayList;
import java.util.List; public class ListTest_Work { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println("Original list : " + list);
System.out.println(); String temp = null;
for (int i = list.size() - 1; i >= 0; i--) {
temp = list.get(i); System.out.println("Check for " + temp);
if ("3".equals(temp)) {
list.remove(temp);
}
}
System.out.println("Removed list : " + list);
} }
2、直接从新创建一个集合,重新摆放,但消耗内存,慎用:
import java.util.ArrayList;
import java.util.List; public class ListTest_Work2 { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println("Original list : " + list);
System.out.println(); List<String> tempList = new ArrayList<String>();
for (String temp : list) {
System.out.println("Check for " + temp);
if (!"3".equals(temp)) {
tempList.add(temp);
}
}
System.out.println("Removed list : " + tempList);
} }
二、ConcurrentModificationException异常-Iterator遍历集合过程中用其他手段(或其他线程)操作元素
ConcurrentModificationException是Java集合的一个快速报错(fail-fast)机制,防止多个线程同时修改同一个集合的元素。在用Iterator遍历集合时,如果你用其他手段(非Iterator自身手段)操作集合元素,就会报ConcurrentModificationException。
不信?用Iterator方式或简写的for(Object o : list) {}方式,遍历集合,修改元素时会报异常:
import java.util.ArrayList;
import java.util.List; public class ListTest2_Unwork { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println("Original list : " + list);
System.out.println(); for (String temp : list) {
System.out.println("Check for " + temp);
if ("3".equals(temp)) {
list.remove(temp);
}
}
System.out.println("Removed list : " + list);
} }
或
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; public class ListTest3_Unwork { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println("Original list : " + list);
System.out.println(); Iterator<String> i = list.iterator();
String temp = null;
while (i.hasNext()) {
temp = i.next();
System.out.println("Check for " + temp);
if ("3".equals(temp)) {
list.remove(temp);
}
}
System.out.println("Removed list : " + list);
} }
日志:
Original list : [1, 2, 3, 4, 5] Check for 1
Check for 2
Check for 3
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at ListTest3_Unwork.main(ListTest3_Unwork.java:20)
在删除元素“3”时,会报异常。
对于此情况,需要用iterator的remove方法替代,结果是妥妥的:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; public class ListTest3_Work { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println("Original list : " + list);
System.out.println(); Iterator<String> i = list.iterator();
String temp = null;
while (i.hasNext()) {
temp = i.next();
System.out.println("Check for " + temp);
if ("3".equals(temp)) {
i.remove();
}
}
System.out.println("Removed list : " + list);
} }
延伸个小问题,为什么for(Object o : list) {}方式遍历集合,现象和Iterator方式一样,都会报错呢?
答:这是因为Java的糖语法,“for(Object o : list) {}方式”只是Java语言用“易用性糖衣”吸引你的手段,本质上,它也是Iterator。不信,你写下下面这段程序,反编译看看就清楚了:
package com.nichagil.test.forloop; import java.util.ArrayList;
import java.util.List; public class ForTester { public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a"); for (String s : list) {
list.remove(s);
System.out.println(s);
}
} }
反编译后是这样的:
package com.nichagil.test.forloop; import java.util.ArrayList;
import java.util.Iterator; public class ForTester {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("a");
Iterator arg2 = list.iterator(); while (arg2.hasNext()) {
String s = (String) arg2.next();
list.remove(s);
System.out.println(s);
} }
}
【Java】集合(List、Set)遍历、判断、删除元素时的小陷阱的更多相关文章
- Java中ArrayList循环遍历并删除元素的陷阱
ava中的ArrayList循环遍历并且删除元素时经常不小心掉坑里,昨天又碰到了,感觉有必要单独写篇文章记一下. 先写个测试代码: import java.util.ArrayList; public ...
- 集合--(List、Set、Map)遍历、删除、比较元素时的小陷阱
6,Map集合遍历的4中方法? 5,List遍历时如何remove元素 4.漏网之鱼-for循环递增下标方式遍历集合,并删除元素 如果你用for循环递增下标方式遍历集合,在遍历过程中删除元素,你可能会 ...
- Java HashMap 如何正确遍历并删除元素
(一)HashMap的遍历 HashMap的遍历主要有两种方式: 第一种采用的是foreach模式,适用于不需要修改HashMap内元素的遍历,只需要获取元素的键/值的情况. HashMap<K ...
- JAVA List 一边遍历一边删除元素
JAVA List 一边遍历一边删除元素,报java.util.ConcurrentModificationException异常 2015年02月10日 14:42:49 zhanzkw 阅读数:3 ...
- Java集合01----ArrayList的遍历方式及应用
Java集合01----ArrayList的遍历方式及应用 前面已经学习了ArrayList的源代码,为了学以 ...
- 【转】ArrayList循环遍历并删除元素的常见陷阱
转自:https://my.oschina.net/u/2249714/blog/612753?p=1 在工作和学习中,经常碰到删除ArrayList里面的某个元素,看似一个很简单的问题,却很容易出b ...
- ArrayList循环遍历并删除元素的常见陷阱
在工作和学习中,经常碰到删除ArrayList里面的某个元素,看似一个很简单的问题,却很容易出bug.不妨把这个问题当做一道面试题目,我想一定能难道不少的人.今天就给大家说一下在ArrayList循环 ...
- ArrayList循环遍历并删除元素的几种情况
如下代码,想要循环删除列表中的元素b,该怎么处理? public class ListDemo { public static void main(String[] args) { ArrayList ...
- java集合 collection-list-ArrayList 将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
import java.util.*; /* 将自定义对象作为元素存到ArrayList集合中,并去除重复元素. 比如:存人对象.同姓名同年龄,视为同一个人.为重复元素. 思路: 1,对人描述,将数据 ...
随机推荐
- eclipse key
让我们按照使用频率来看看我最爱用的一些热键组合.(注:以下内容在Eclipse3.02及一上版本通过测试) . Control-Shift-T: 打开类型(Open type).如果你不是有意磨洋工, ...
- PHP5各个版本的新功能和新特性总结(转载 http://www.jb51.net/article/48150.htm)
本文目录:PHP5.2 以前:autoload, PDO 和 MySQLi, 类型约束PHP5.2:JSON 支持PHP5.3:弃用的功能,匿名函数,新增魔术方法,命名空间,后期静态绑定,Heredo ...
- php 无限循环
什么是无限分类呢?就像windows下新建一个文件夹,在新建的文件夹下又可以新建 一个文件夹,这样无限循环下去,无限分类也是这样,父类可以分 出它子类,子类又 可以分出它的子类,这样一直无限循环下去. ...
- paper 44 :颜色矩和颜色相关图(color correlogram)
- oracle的散列聚簇表
在簇表中,Oracle使用存储在索引中的键值来定位表中的行, 而在散列聚簇表中,使用了散列函数代替了簇索引,先通过内部函数或者自定义的函数进行散列计算,然后再将计算得到的码值用于定位表中的行. 创建散 ...
- PAT乙级 1001. 害死人不偿命的(3n+1)猜想 (15)
1001. 害死人不偿命的(3n+1)猜想 (15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 卡拉兹(Ca ...
- 仅支持webkit浏览器的多行内容超出显示省略号
.box { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; ...
- 【DP水题】投票问题(二)
投票问题(一) [试题描述] 欧阳文和欧阳武竞选学联主席,汪梁森负责唱票,共有m+n张,结果欧阳文获胜,已知欧阳文和欧阳武分别获得 m 张票和 n 张票(m>n).现在请你计算在唱票过程中欧阳文 ...
- 一个Convert、TryParse数据转换的问题
今天在进行数据转换的时候遇到一个问题,记录下,希望看到的童鞋有点用哦~ Convert.ToInt32(0.80155023553515) 结果为1 但是以下的做法,就不是想当然的结果咯~ int.T ...
- fix org.openqa.selenium.NoSuchWindowException when find element on ie11.
Steps:1.I was able to resolve the issue after adding the site URL under trusted sites of IE. The sam ...