Iterator 接口 也是Java集合框架成員,它主要用來遍歷(即迭代訪問)Collection集合中的元素,Iterator 對象也稱爲迭代器
boolean hasNext(): 如果迭代中的集合元素沒有被遍歷完,則返回
true
Object next(): 返回集合中的下一個元素
- void remove(): 刪除集合裏上一次next方法返回的元素
Iterator模式是用於遍歷集合類的標準訪問方法。它可以把訪問邏輯從不同類型的集合類中抽象出來,從而避免向客戶端暴露集合的內部結構。
for進行刪除
- 可以正常刪除元素
- 由於執行list.remove(i),list的長度減少了1,若是直接返回list.get(i)返回的是list.get(i+1)的值
- 如果想正常的獲取刪除的值可以先定義
String str =null
,再用str = list.get(i)
,最後在執行remove方法就可以獲取刪除元素的值了
list裏面有a,b,c,d,e 元素
@Test
public void testForRemove() {
forRemove(list, "b");
for(String str:list) {
System.out.print(str+"\t");
}
}
/*
* 1. list.remove()成功時,list的長度變小一位
*
* 2.這裏獲取刪除元素的值,list.get(i)獲取刪除的值,變爲了list.get(i+1)的值
*/
public static void forRemove(List<String> list,String target){
for(int i = 0;i<list.size();i++){
if(list.get(i).equals(target)){
list.remove(i);
//本來應該輸出b,但是卻輸出c
System.out.print(list.get(i)+"\t");
}
}
}
forRemove
這種方法,數據量大時,效率特別低
Iterator刪除
public static void IteratorRemove(List<String> list,String target){
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String s = iterator.next();
if(s.equals(target)){
iterator.remove();
}
}
}
Itreator 必須依附於Collection 對象,Iterator 迭代器採用的是快速失敗(fail-fast)機制,一旦迭代過程中檢測到該集合已經被修改(通常是程序中的其他線程修改),程序立即引發ConcurrentModificationException異常,而不是顯示修改後的結果,這樣可以避免共享資源引發的潛在問題
注意:
foreach(加強for循環)進行刪除會出問題
循環迭代訪問元素集合更加便捷,但是foreach循環中迭代變量也不是集合本身,當進行刪除操作時,直接使用list.remove(),並不能在用於刪除集合。對於加強for循環,經過編譯後採用的是迭代器模式,來遍歷,當進行刪除,修改時會引發fail-fast(快速失敗)
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String str : list) {
if(str.equals("aaa")) {
list.remove("aaa");
}
}
}
}
反編譯後可以看到,foreach使用的
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
Iterator var3 = list.iterator();
while (var3.hasNext()) {
String str = (String) var3.next();
if (str.equals("aaa")) {
list.remove("aaa"); //直接使用list.remove
}
}
}
安全失敗(fail—safe)
採用安全失敗機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先複製原有集合內容,在拷貝的集合上進行遍歷。
原理:由於迭代時是對原集合的拷貝進行遍歷,所以在遍歷過程中對原集合所作的修改並不能被迭代器檢測到,所以不會觸發ConcurrentModificationException。
缺點:基於拷貝內容的優點是避免了ConcurrentModificationException,但同樣地,迭代器並不能訪問到修改後的內容,即:迭代器遍歷的是開始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發生的修改迭代器是不知道的。
場景:java.util.concurrent包下的容器都是安全失敗,可以在多線程下併發使用,併發修改。
參考1: Hollis直面java第45期
參考2: Java瘋狂講義