文章

集合遍历的时候删除元素的方法

集合遍历的时候删除元素的方法

在看阿里巴巴java开发手册时,有一条建议是这样的。

【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

反例:

1
2
3
4
5
6
7
8
9
10
11
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
for (Integer item : list) {
    if (item == 3) {
        list.remove(item);
    }
}

说明:这个例子的执行结果会出乎大家的意料,那么试一下把”1”换成”2”,会是同样的结果吗?

此时程序会抛出并发修改异常: java.util.ConcurrentModificationException

我们将ArrayList 换成 LinkedList 后,结果也是一样的

使用对ArrayList索引遍历,并删除每个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
System.out.println("befor: " + list.size());
for (int i = 0; i < list.size(); i++) {
    list.remove(i);
}
for (String item : list) {
    System.out.println(item);
}
System.out.println("after: " + list.size());

结果如下:

1
befor: 3222after: 1

此时我们再尝试使用map做同样的操作,可以看到map的几种遍历方法都不能正确的删除

1
2
3
4
5
6
7
8
9
10
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
for (Integer integer : map.keySet()) {
    map.remove(integer);
}
for (Map.Entry<Integer, Integer> item : map.entrySet()) {
    map.remove(item.getKey());
}

正例:

1
2
3
4
5
6
7
Iterator<String> it = a.iterator();
while (it.hasNext()) {
    String temp = it.next();
    if (删除元素的条件) {
        it.remove();
    }
}

同样地,对于HashMap, 也采用迭代器的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    if (iterator.next().getKey() == 2) {
        iterator.remove();
    }
}
map.forEach((k, v) -> {
    System.out.println("key: " + k + "  value: " + v);
});

可以得到如下结果:

1
2
key: 1  value: 1
key: 3  value: 3
本文由作者按照 CC BY 4.0 进行授权