• java HashSet迭代器删除、添加元素


    第一次遇到这个问题,有必要记录一下。昨天在测试程序的时候出现这么个异常:

    Exception in thread "main" java.util.ConcurrentModificationException
    	at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
    	at java.util.HashMap$KeyIterator.next(Unknown Source)
    	at com.rick.model.Relation.getBack(Relation.java:1500)
    	at com.rick.model.Relation.getConMap(Relation.java:1447)
    	at com.rick.model.Run.main(Run.java:74)
    

    ConcurrentModificationException(并发修改异常)。编译器提示异常抛出行位于set迭代器处,相比就是在遍历set时出现了问题,附上我的代码(逻辑项目,有点复杂,递归,求笛卡儿积):

    //*下面一段代码无法正常运行

      1 public static HashSet<HashSet<Relation>> getBack(Relation temp_con){
      2         HashSet<HashSet<Relation>> return_set = new HashSet<HashSet<Relation>>();//这个return_set是返回用的,在最后用到
      3         HashSet<HashSet<HashSet<Relation>>> set0 = new HashSet<HashSet<HashSet<Relation>>>();//checked
      4         
      5         Iterator<HashSet<Relation>> it = temp_con.getBigSet().iterator();
      6         // for testing
      7     /*    while(it.hasNext()){
      8             HashSet<Relation> small_set = it.next();
      9             Iterator<Relation> ittt = small_set.iterator();
     10             System.out.println("this is a small set");
     11             while(ittt.hasNext()){
     12                 Relation rett = ittt.next();
     13                 System.out.println("hahahah" + rett.toString());
     14             
     15             }
     16         }*/
     17         
     18         while(it.hasNext()){
     19             HashSet<Relation> small_set = it.next();
     20             //这是在算法描述中一直说到的新的set
     21             HashSet<Relation> new_set = new HashSet<Relation>();
     22             // 我都不知道了
     23             Iterator<Relation> it1 = small_set.iterator();
     24             while(it1.hasNext()){
     25                 Relation rt = it1.next();
     26                 if (rt.getType() == 0){
     27                     new_set.add(rt);
     28                 }     
     29                 else if (rt.getType() == 2 )
     30                     set0.add(getBack(rt));
     31                 }
     32 
     33 
     34                 if(set0.size() > 1){
     35                     Iterator<HashSet<HashSet<Relation>>> it0 = set0.iterator();
     36                     while(it0. hasNext()){
     37                         
     38                         HashSet<HashSet<Relation>> set1 = it0.next();
     39                         HashSet<HashSet<Relation>> set_delete = null;//用来引用待会儿出现的set2,以便将set2从set0中remove
     40                     
     41                         Iterator<HashSet<Relation>> its1 = set1.iterator();
     42                         while(its1.hasNext()){
     43                             HashSet<HashSet<Relation>> set123 = new HashSet<HashSet<Relation>>();
     44                             HashSet<Relation> set11 = its1.next();
     45                             Iterator<Relation> it11 = set11.iterator();
     46                             if(it0.hasNext()){
     47                                 HashSet<HashSet<Relation>> set2 = it0.next();
     48                                 set_delete = set2;
     49                                 Iterator<HashSet<Relation>> its2 = set2.iterator();
     50                                 while(its2.hasNext()){
     51                                     HashSet<Relation> temp_set = new HashSet<Relation>(new_set);
     52                                     HashSet<Relation> set21 = its2.next();
     53                                     Iterator<Relation> it21 = set21.iterator();
     54                                     while(it11.hasNext()){
     55                                         Relation foradd = it11.next();
     56                                         if(!temp_set.contains(foradd)){
     57                                             temp_set.add(foradd);
     58                                         }
     59                                     }
     60                                     it11 = set11.iterator();//每次得重新指向set11的开头
     61                                     while(it21.hasNext()){
     62                                         Relation foradd = it21.next();
     63                                         if(!temp_set.contains(foradd)){
     64                                             temp_set.add(foradd);
     65                                         }
     66                                     }
     67                                     //于是添加新产生的集合
     68                                     //HashSet<HashSet<Relation>> set123 = new HashSet<HashSet<Relation>>();
     69                                     set123.add(temp_set);
     70                                     //要放入set0和后面一起求笛卡尔积
     71                                     
     72                                 }// its2 的 while 结束了
     73                             }// if has next
     74                             set0.add(set123);
     75                             set0.remove(set1);
     76                             set0.remove(set_delete);
     77                         }
     78                     }//
     79             }// END OF if 
     80             else if(set0.size() == 1){
     81                 Iterator<HashSet<HashSet<Relation>>> it0 = set0.iterator();
     82                 HashSet<HashSet<Relation>> set1 = it0.next();
     83                 Iterator<HashSet<Relation>> its1 = set1.iterator();
     84                 while(its1.hasNext()){
     85                     HashSet<Relation> set11= its1.next();
     86                     set11.addAll(new_set);
     87                 }    
     88             }
     89                 
     90                 
     91             Iterator<HashSet<HashSet<Relation>>> it0 = set0.iterator();
     92             while(it0.hasNext()){
     93                 Iterator<HashSet<Relation>> it9 = it0.next().iterator();
     94                 while(it9.hasNext()){
     95                     System.out.println("啦啦啦,我是卖报的小行家");
     96                     return_set.add(it9.next());
     97                 }
     98             }
     99             if(set0.size()<1){
    100                 return_set.add(new_set);
    101             }
    102             System.out.println("return_set ' s size() is "+ return_set.size());
    103                 
    104         }// END OF OUTER WHILE
    105         
    106         
    107     return return_set;
    108 
    109     }

     编译器提示的“at com.rick.model.Relation.getBack(Relation.java:1500)”就位于上一段代码的第35行。

    看了下Java 的API文档,上网查了一下,大家讨论的普遍是用迭代器遍历set删除元素时抛出“并发修改异常”,但我的问题好像要复杂不少,至少现在(2014.4.20上午)尚未找到解决办法(可能会放弃set而使用List,但还是想继续把问题搞明白点)。

    来自网络:

    Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

      


      先来一下普通的迭代器Iterator)遍历删除元素的解决方案:

      

     最理想的方法应该是使用Iterator类的remove()方法:

        void remove()

        从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

      所以在程序中运用it.remove()即可成功删除元素

      还有一种比较不错的方法是用HashSet的clone()方法拷贝给另一个临时的HashSet,然后用这个拷贝的HashSet的迭代器来完成原始HashSet的删除工作。

        Object clone()
              返回此 HashSet 实例的浅表副本:并没有复制这些元素本身。


    添加元素的问题尚在研究之中。。。 

  • 相关阅读:
    单例设计模式
    程序员眼中的中国传统文化王阳明《传习录》10
    程序员眼中的中国传统文化王阳明《传习录》8
    程序员眼中的中国传统文化王阳明《传习录》16
    程序员眼中的中国传统文化王阳明《传习录》11
    程序员眼中的中国传统文化王阳明《传习录》15
    程序员眼中的中国传统文化王阳明《传习录》14
    程序员眼中的中国传统文化王阳明《传习录》9
    程序员眼中的中国传统文化王阳明《传习录》13
    程序员眼中的中国传统文化王阳明《传习录》12
  • 原文地址:https://www.cnblogs.com/shaozhiheng/p/3676005.html
Copyright © 2020-2023  润新知