cvmachine.com - 申博开户网

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

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

2019-04-20 08:19:34 来历:www.cvmachine.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.cvmachine.com/dnjc/100437.html
Tags: 进行 循环 foreach
修改:申博开户网
关于咱们 | 联络咱们 | 友情链接 | 网站地图 | Sitemap | App | 回来顶部