本文最后更新于616 天前,其中的信息可能已经过时,如有错误请发送邮件到434658198@qq.com
问题
最近写代码发现了一个BUG,在使用增强for循环(foreach)时报错
问题代码1:增强for循环(foreach)
public static void main(String[] args) {
List<String> list = new ArrayList<>(4);
list.add("a");
list.add("ab");
list.add("abc");
list.add("abcd");
for (String str : list) {
if (str.contains("a")) {
list.remove(str);
}
}
System.out.println(list);
}
错误日志
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
Concurrent Modification Exception的意思是并发修改异常,通过异常信息可以发现在数据删除后继续遍历时,在 ConcurrentModificationException 方法出抛出异常
当时并没有在意这个问题,我直接换了个写法[普通for循环(for-i)]继续循环删除,直到测试的时间发现了一个非常严重的问题:数据丢失
问题代码2:普通for循环(for-i)
public static void main(String[] args) {
List<String> list = new ArrayList<>(4);
list.add("a");
list.add("ab");
list.add("abc");
list.add("abcd");
for (int i = 0; i < list.size(); i++) {
if (list.get(i).contains("a")) {
list.remove(i);
}
}
System.out.println(list);
}
输出结果
[ab, abcd]
可以看到删掉“a”后“abc”缺失
测试后发现这样一个大BUG,查了资料后,发现这是因为在删除 “a”后,剩余的元素会整体向前移动一位,而坐标值仍是递增的,所以下一个坐标元素值相当于当前删除元素的下下一位元素值。
代码整改
发现这个问题后很快就找到了解决方法
if (list.get(i).contains("a")) {
list.remove(i);
i--;
}
可以在删除元素时,将坐标值减 1就可以解决
代码优化
我在查阅资料和别人博客的时间,发现我这样写是错误的,不能这样删除List中的元素
以下优化代码摘自其他博客
使用迭代器(Iterator)
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
// 删除元素
iterator.remove();
}
JDK8后lambda写法
list.removeIf(s -> s.contains("a"));
我个人更推荐使用lambda表达式写法,更简洁