45fan.com - qg777钱柜

搜索: 您的位置主页 > 电脑频道 > 电脑教程 > 阅读资讯:为什么不能在foreach循环进行remove/add操作?

为什么不能在foreach循环进行remove/add操作?

2019-04-20 08:19:34 来源:www.45fan.com 【
废话少说,直接上测试代码:
public class ForeachTest { public static void main(String[] args){ List<String> list = new ArrayList<>(); list.add("hello"); list.add("hello1"); list.add("hello2"); // for (int i = 0; i < list.size(); i++) { for(String s:list){ list.remove("hello"); System.out.println(s); } } }
结果如下:
为什么不能在foreach循环进行remove/add操作?
然后换一种遍历方式:
public class ForeachTest { public static void main(String[] args){ List<String> list = new ArrayList<>(); list.add("hello"); list.add("hello1"); list.add("hello2"); for (int i = 0; i < list.size(); i++) { // for(String s:list){ list.remove("hello"); System.out.println(list.get(i)); } } }
结果如下:
为什么不能在foreach循环进行remove/add操作?
以上是两种测试的对比现象(结果),那么既然有了结果接下来就要分析原因了。
控制台抛异常首先定位异常抛出的地方,通过查看ArrayList源码可以得知异常触发点为:
为什么不能在foreach循环进行remove/add操作? 可知,异常的原因是因为modCount != expectedModCount导致的。
接下来就是分别查看这两个参数的含义和可以修改他们的操作了。
  • modCount:是AbstractList的一个成员变量: protected transient int modCount = 0; 但是ArrayList是继承AbstractList的,这里modCount的修饰符是protected,所以是可以被subclass继承的。
    继续查看源码,对modCount的英文解释为:
    The number of times this list has been <i>structurally modified</i>.翻译:记录该list结构被修改的次数。 查看源码中该变量的修改情况,发现就是在add/remove的时候,修改了modeCount的值。
  • expectedModCount:是ArrayList的一个内部类的成员变量
    为什么不能在foreach循环进行remove/add操作?
    说明:这里我们知道增强for底层的实现还是通过Iterator实现的,所以这里就不难理解为什么出现在这个地方了。
  • 在Iterator遍历开始就设置了两个参数相等,那么是什么情况导致了两个参数不等呢?
    前面我们知道在对集合进行add和remove的时候会修改modCount的值,而我们整个iterator都没有修改expectedModCount的值,所以在我们使用增强for遍历的时候,如果进行add/remove的操作,就会导致两个参数不等,然后抛出异常。
fail-fast机制:以上我们是从代码层面分析出了,为什么抛出异常,但是我们其实还不是很清楚为什么要这么设计。其实这是Java的fail-fast 机制,即快速失败机制,是java集合(Collection)中的一种错误检测机制。
详细解释如下: 为什么不能在foreach循环进行remove/add操作?
上面我们基本了解了异常原因和原理,接下来的问题就是我们该如何在业务中处理这种情况呢?
  1. 第一种方式:我们使用一般的for循环即可;
  2. 第二种方式:我们使用Iterator自带的remove方法进行操作,因为自带的方法是同步了modCount和expecteModCount的;
  3. 第三种方式:使用Java8中的filter;
  4. 第四种方式:新建一个集合来装过滤后的数据(这种方式比较消耗内存,不推荐使用);
  5. 第N种方式:已经知道原因和原理了,其实处理方式就很灵活了,可以自己想想其他方式了,哈哈!!!
 
 

本文地址:http://www.45fan.com/dnjc/100437.html
Tags: 进行 循环 foreach
编辑:qg777钱柜
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部