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 實例的淺表副本:並沒有復制這些元素本身。

 

 


 

添加元素的問題尚在研究之中。。。 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM