在對List、Set、Map執行遍歷刪除或添加等改變集合個數的操作時,不能使用普通的while、for循環或增強for。會拋出ConcurrentModificationException異常或者沒有達到刪除的需求。在遍歷時刪除元素,需要使用迭代器的方式。
## ArrayList源碼中說明的報異常原因:
~~~
?* <p>The iterators returned by this class's <tt>iterator</tt> and
?* <tt>listIterator</tt> methods are <i>fail-fast</i>: if the list is
?* structurally modified at any time after the iterator is created, in any way
?* except through the iterator's own <tt>remove</tt> or <tt>add</tt> methods,
?* the iterator will throw a {@link ConcurrentModificationException}. ?Thus, in
?* the face of concurrent modification, the iterator fails quickly and cleanly,
?* rather than risking arbitrary, non-deterministic behavior at an undetermined
?* time in the future.<p>
~~~
(翻譯:通過類的iterator和listiterator方法獲取到的迭代器是快速失敗迭代器:如果list在迭代器生成之后發生了結構性的改變,迭代器將拋出ConcurrentModificationException,**但是當使用迭代器自己的remove或add方法時,不會拋出此異常。**也就是說,當面對并發修改時,迭代器快速失敗,而不是冒在未來不確定的時間發生不確定的行為的危險。)
~~~
?* Note that the fail-fast behavior of an iterator cannot be guaranteed
?* as it is, generally speaking, impossible to make any hard guarantees in the
?* presence of unsynchronized concurrent modification. ?Fail-fast iterators
?* throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
?* Therefore, it would be wrong to write a program that depended on this
?* exception for its correctness: <i>the fail-fast behavior of iterators
?* should be used only to detect bugs.</i><p>
~~~
(翻譯:需要注意的是迭代器**不保證快速失敗行為一定發生**,因為一般來說不可能對是否發生了不同步并發修改做任何硬性的保證。快速失敗迭代器會盡最大努力拋出ConcurrentModificationException異常。因此,寫一個通過是否出現這種異常來判斷是否正確的程序是錯誤的。快速失敗行為的正確用法是僅用于檢測異常。)
## 代碼示例:
~~~
public class CollectionRemoveDemo {
public static void main(String[] args) {
ListRemove();
System.out.println("-----------------------------------------------------------------------------------------------");
SetRemove();
System.out.println("-----------------------------------------------------------------------------------------------");
MapRemove();
}
public static void ListRemove(){
List<String> strList = new ArrayList<String>();
strList.add("aaaa");
strList.add("bbbb");
strList.add("cccc");
strList.add("cccc");
strList.add("dddd");
for(String str : strList){
System.out.println(str);
}
System.out.println("init List size:" + strList.size());
Iterator<String> it = strList.iterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("cccc")){
it.remove();
}
}
for(String str : strList){
System.out.println(str);
}
System.out.println("removed List size:" + strList.size());
}
public static void SetRemove(){
Set<String> strSet = new TreeSet<String>();
strSet.add("aaaa");
strSet.add("bbbb");
strSet.add("cccc");
strSet.add("cccc");//重復的數據將不會再次插入
strSet.add("dddd");
for(String str : strSet){
System.out.println(str);
}
System.out.println("Init Set size:" + strSet.size());
Iterator<String> it = strSet.iterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("cccc")){
it.remove();
}
}
for(String str : strSet){
System.out.println(str);
}
System.out.println("removed Set size:" + strSet.size());
}
public static void MapRemove(){
Map<String, String> strMap = new TreeMap<String, String>();
strMap.put("a", "aaaa");
strMap.put("b", "bbbb");
strMap.put("c", "cccc");
strMap.put("d", "dddd");
for(String key : strMap.keySet()){
System.out.println(key + " : " + strMap.get(key));
}
System.out.println("Init Map size:" + strMap.size());
Iterator<Entry<String,String>> it = strMap.entrySet().iterator();
while(it.hasNext()){
Entry<String,String> strEntry = it.next();
if(strEntry.getKey().equals("c")){
it.remove();
}
}
for(String key : strMap.keySet()){
System.out.println(key + " : " + strMap.get(key));
}
System.out.println("removed Map size:" + strMap.size());
}
}
~~~