项目遇到了题目所述的问题,还是折腾了一会...
现在总结一下:
这里写一个测试小程序:
List<Integer> ints = new ArrayList<Integer>();
for (int i =
0; i < 100; i++) {
ints.add(i);
}
我们把里面不能整除3的对象都删除...
首先,最容易想到的,foreach循环,判断删除...
for (Integer integer : ints) {
if (integer % 3 != 0) {
ints.remove(integer);
}
}
运行一下,异常:
java.util.ConcurrentModificationException
这里不详细解释了,最后会给出我参考的那个网页.
简单的说:foreach其实是iterator实现的,而iterator不允许在集合使用自身的时候删除,所以就抛出了前面给的异常.
然后写传统型的for循环吧:
int length = ints.size();
for (int i = 0; i < length; i++) {
if (ints.get(i) % 3 != 0) {
ints.remove(i);
}
}
运行一下,异常:java.lang.IndexOutOfBoundsException
原因是随着元素的删除,List的size发生了变化,但是index没有变化,就会造成index>=size的情况发生,到了后面就越界了...
问题是我习惯于先计算长度再开始循环,因为每次计算size有性能损失...
好吧,只好每次都计算size了:
for (int i = 0; i < ints.size(); i++) {
if (ints.get(i) % 3 != 0)
{
ints.remove(i);
}
}
运行一下,可以跑通,但是结果不正确...
0
2
3
5
6
8
原因是删除之后index对应不上了呵呵...
现在使用奇技淫巧:
for (int i = 0; i < ints.size(); i++) {
if (ints.get(i) % 3 != 0)
{
ints.remove(i);
i--;
}
}
每次满足条件删除一个之后,我们把index减少一个,这样就能保证正常运行了...
但是:但是这绝对不是一个好办法...
其实iterator也提供了remove方法,用这个:
前提是没有其他线程在操作这个list,即若有多个操作者同时操作这个list其结果不见得会对。
Iterator<Integer> iterator = ints.iterator();
while
(iterator.hasNext()) {
Integer temp = iterator.next();
if (temp
% 3 != 0) {
iterator.remove();
}
}
如果你删除的个数是3个,IndexOutOfBoundsException是不会发生的,但是删除后的List不是你想要的结果。具体是
private void unSafeDeleteTopByCount(int count) {
try {
for (int i = 0; i < count; i++) {
list.remove(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
print();
}
}
private void print() {
for (String str : list) {
System.out.println(str);
}
}
List<String> list = new ArrayList<String>();
for(int i=0;i<6;i++){
list.add("str"+i);
}
unSafeDeleteTopByCount(3);
打印出的结果是:
str1
str3
str5
为什么呢,当我们删除了index为0的元素【str0】后,由于List的size变化,index为0的元素会变为str1,而index为1的元素会变为str2.