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

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>getBack(Relation temp_con){2 HashSet> return_set = new HashSet>();//这个return_set是返回用的,在最后用到
3 HashSet>> set0 = new HashSet>>();//checked
4
5 Iterator> it =temp_con.getBigSet().iterator();6 //for testing
7 /*while(it.hasNext()){8 HashSet small_set = it.next();9 Iterator 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 small_set =it.next();20 //这是在算法描述中一直说到的新的set
21 HashSet new_set = new HashSet();22 //我都不知道了
23 Iterator 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>> it0 =set0.iterator();36 while(it0. hasNext()){37
38 HashSet> set1 =it0.next();39 HashSet> set_delete = null;//用来引用待会儿出现的set2,以便将set2从set0中remove
40
41 Iterator> its1 =set1.iterator();42 while(its1.hasNext()){43 HashSet> set123 = new HashSet>();44 HashSet set11 =its1.next();45 Iterator it11 =set11.iterator();46 if(it0.hasNext()){47 HashSet> set2 =it0.next();48 set_delete =set2;49 Iterator> its2 =set2.iterator();50 while(its2.hasNext()){51 HashSet temp_set = new HashSet(new_set);52 HashSet set21 =its2.next();53 Iterator 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> set123 = new HashSet>();
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>> it0 =set0.iterator();82 HashSet> set1 =it0.next();83 Iterator> its1 =set1.iterator();84 while(its1.hasNext()){85 HashSet set11=its1.next();86 set11.addAll(new_set);87 }88 }89
90
91 Iterator>> it0 =set0.iterator();92 while(it0.hasNext()){93 Iterator> 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 returnreturn_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

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

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

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

Object

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

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