本文版权归作者所有,仅供用来网上学习来用,读者可以收藏,请不要下载到本机或重新发布到其它网站
先看一个例子:
import java.util.ArrayList;
import java.util.List;
public class CollectionOperation {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf(i));
}
for (String str : list) {
if (str.equals("5")) {
list.remove(str);
}
}
}
}
这个程序可以通过编译,但在运行时会出现异常,异常信息如下:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at CollectionOperation.main(CollectionOperation.java:12)
为什么会出现这种异常呢?因为在执行到第14行时,list的长度发生了变化,由原来的10变为9。第12行的for (String integer : list)这种循环是在JDK5以后才支持的。而这种循环对于集合类来说,会生成一个迭代对象Iterator,然后进行遍历的。在每次循环之前,它会检查集合类当前的长度是否发了变化,如果发生变化就会抛出如上的异常。对于ArrayList, 这段检查的代码是这样的(此段代码是写在AbstractList类的内部类Itr中):
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
因此,这种JDK5新规范的循环的写法,虽然简单,但是如果有对集合类对象有添加和删除的操作时,会出现这种异常。这时需要用常归的循环的写法了。
import java.util.ArrayList;
import java.util.List;
public class CollectionOperation {
public static void main1(String[] args) {
int size = 10;
List<String> list = new ArrayList<String>();
for (int i = 0; i < size; i++) {
list.add(String.valueOf(i));
}
for (int i = 0; i < size; i++) {
String str = list.get(i);
if (str.equals("5")) {
list.remove(str);
}
}
}
}
我们写程序一般很少在遍历的时候添加元素,多数是在遍历的时候,找到匹配的元素,然后进行删除操作。就像上面的例子一样,但是细心的朋友会发现,上面的例子有隐患存在。重新更改一下上面的例子,这个隐患就会暴露出来。
import java.util.ArrayList;
import java.util.List;
public class CollectionOperation {
public static void main1(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf(5));
}
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
if (str.equals("5")) {
list.remove(str);
}
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
只更改了一下第10行的值为5,也就是List中存放的都是5,对于后面的删除操作,我们本来是打算删除列表中值等于5的元素,即删除List中的全部元素,运行一下程序,我们发现,并没有完全删除,而是剩下了5个元素。
再看一个更奇怪的例子,还是这样的循环,我们删除一个数列上偶数位上的数,只留奇数位上的数。例如:原数列为10、20、30、40、50、60、70、80、90、100,则偶数位上的数为20、40、60、80、100,删除后剩余的数为:10、30、50、70、90。一般人会写出下面的错误程序:
public class CollectionOperation {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
list.add((i + 1) * 10);
}
for (int i = 0; i < list.size(); i++) {
if ((i + 1) % 2 == 0) {
list.remove(i);
}
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i) +" ");
}
}
}
猛一看这个程序,是对的,可是一运行出来结果就不对。这个程序的结果是:
10 30 40 60 70 90 100
这个结果并不是我们想要的,但是到底哪里出错了?因为是因为集合类List为可变长的数组,当删除中间一个元素后,这个被删除元素的后面的元素会向前移动一个,即元素的索引变小了,但是循环变量i是没有变化的,这时再向后遍历时,会漏掉刚删除那个元素上新移进的元素。这样一直往复,直到结束。
怎样解决这个问题呢?
改换一下思路,因为删除元素的时候,后面的元素都是向前移动,因此,我们这样循环:
for (int i = list.size(); i >= 0; i--) {
if ((i + 1) % 2 == 0) {
list.remove(i);
}
}
再试一下,结果正确了:
10 30 50 70 90
这种循环很常见,也很有效果,且效率很高。因为List的size方法只被调用了一次。在JDK的原码中,很多listener的遍历都是用的倒序。
分享到:
相关推荐
实现整数集合的各种操作,还对姐妹面进行了简单的美化工作
C++编程:建造集合类实训,集合的各种操作类C++代码
本文实例讲述了C#集合遍历时删除和增加元素的方法。分享给大家供大家参考,具体如下: 大多数时候,遍历集合元素的时候并不需要对元素进行增加或者删除操作,但有些时候则需要,比如,如果集合中盛放的元素是社会上...
使用java语言写的自定义集合类,非常好用的集合类,可以实现集合的一些操作。
实现复数集合类 要求:1、实现两个类:集合类(Cassemblage )和复数类(Cmycomplex)。 2、输入:分别输入集合中元素个数和元素(实部和虚部)。 3、输出:按照复数模的大小从小到大输出,不考虑两个复数模相等...
Java常用类 Math类 String类 StringBuffer类 StringTokenizer类 包装类 集合操作 集合 列表(List) 映射(Map) Collections类 枚举和迭代
java集合类框架图
第13讲 JAVA集合类.ppt第13讲 JAVA集合类.ppt第13讲 JAVA集合类.ppt第13讲 JAVA集合类.ppt第13讲 JAVA集合类.ppt
set list ArrayList等java集合类详述
实现Comparable接口或Comparator接口,用户可以根据需要对集合中的元素进行排序。为了方便用户使用,Java平台还提供了Collections和Arrays工具类。collection.rar分别对上述内容进行详细讲解演示。
java的各种集合类的总结,以及实例讲解。
有关java集合类的一些代码,一般供参考用。。。。
jstl字符串集合类的例子 jstl字符串集合类的例子
Java 集合排序 及java集合类 详解.pdf
java集合类java集合类java集合类java集合类java集合类java集合类java集合类java集合类java集合类java集合类
java集合类线程安全 写的不错,短小精悍,值得一读
C#的6种常用集合类大比拼C#的6种常用集合类大比拼
java基本集合类
用java编写一个纯数组实现的集合类,可以实现增删改查操作