當前位置:首頁 » 網路管理 » 增強for循環為什麼可以刪除
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

增強for循環為什麼可以刪除

發布時間: 2022-08-02 16:13:20

① HashMap和List遍歷方法總結及如何遍歷刪除

(一)List的遍歷方法及如何實現遍歷刪除
我們造一個list出來,接下來用不同方法遍歷刪除,如下代碼:
List<String> list= new ArrayList<String>();famous.add("zs");famous.add("ls");famous.add("ww");famous.add("dz");

1、for循環遍歷list:
for(int i=0;i<list.size();i++){if(list.get(i).equals("ls"))list.remove(i);}

這是一種很常見的遍歷方式,但是使用這種遍歷刪除元素會出現問題,原因在於刪除某個元素後,list的大小發生了變化,而你的索引
也在變化,所以會導致你在遍歷的時候漏掉某些元素。比如當你刪除第一個元素後,繼續根據索引訪問第二個元素後,因為刪除的原因,
後面的元素都往前移動了以為,所以實際訪問的是第三個元素。因此,這種遍歷方式可以用在讀取元素,而不適合刪除元素。
2、增強for循環:
for(String x:list){if(x.equals("ls"))list.remove(x);}

這也是一種很常見的遍歷方式,但是使用這種遍歷刪除元素也會出現問題,運行時會報異常
其實增強for循環是java語法糖的一種體現,如果大家通過反編譯得到位元組碼,那麼上面這段代碼的內部實現如下所示:

for(Iterator<String> it = list.iterator();it.hasNext();){String s = it.next();if(s.equals("madehua")){list.remove(s);}}

下面就解釋為什麼會報異常。分析Iterator的源代碼,重點分析整個調用該過程中的
函數(hasNext和remove):

private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; // size為集合中元素的個數 } public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new (); cursor = i + 1; return (E) elementData[lastRet = i]; } /* 此方法並沒被調用,只是調用List.remove方法 public void remove() { checkForComodification(); try { ArrayList.this.remove(lastRet); // size欄位減1 cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new (); } } */ final void checkForComodification() { // 檢查修改和當前版本號是否一致,不一致則拋出異常 if (modCount != expectedModCount) throw new (); } } // List.remove @Override public boolean remove(Object object) { Object[] a = array; int s = size; if (object != null) { for (int i = 0; i < s; i++) { if (object.equals(a[i])) { System.array(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 核心代碼:修改了版本號。這樣當checkForComodification的時候,modCount值就和expectedModCount不同 return true; } } } else { for (int i = 0; i < s; i++) { if (a[i] == null) { System.array(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; return true; } } } return false; }

接下來梳理一下流程,這時候你就會發現這個異常是在next方法的checkForComodification中拋出的。拋出的原因是
modCount !=expectedModCount。這里的modCount是指這個list對象從呢我出來到現在被修改的次數,當調用list
的add或者remove方法的時候,這個modCount都會自動增減;iterator創建的時候modCount被復制給了
expectedModcount,但是調用list的add和remove方法的時候不會同時自動增減expectedModcount,這樣就導致
兩個count不相等,從而拋出異常。大家如果理解了上面的執行流程,以後碰到類似這種問題,比如如果刪除的是倒數
第二個元素卻不會碰到異常。就會知道為什麼了。

3、iterator遍歷刪除:

Iterator<String> it = list.iterator();while(it.hasNext()){String x = it.next();if(x.equals("del")){it.remove();}}

這種方式是可以正常遍歷和刪除的。但是你可能看到上面代碼感覺和增強for循環內部實現的代碼差不多,其實差別就在於上面使用
一個使用list.remove(),一個使用it.remove()。

(二)HashMap的遍歷刪除及如何實現遍歷刪除
一樣我們先造一個hashmap出來,如下:

private static HashMap<Integer, String> map = new HashMap<Integer, String>();; public static void main(String[] args) { for(int i = 0; i < 10; i++){ map.put(i, "value" + i); } }

1、第一種遍歷刪除:

for(Map.Entry<Integer, String> entry : map.entrySet()){Integer key = entry.getKey();if(key % 2 == 0){System.out.println("To delete key " + key);map.remove(key);System.out.println("The key " + + key + " was deleted");}

這種遍歷刪除依舊會報異常,
2、第二種遍歷刪除:
Set<Integer> keySet = map.keySet(); for(Integer key : keySet){ if(key % 2 == 0){ System.out.println("To delete key " + key); keySet.remove(key); System.out.println("The key " + + key + " was deleted"); } }

這種遍歷刪除依舊會報異常,
3、第三種遍歷刪除:
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();while(it.hasNext()){Map.Entry<Integer, String> entry = it.next();Integer key = entry.getKey();if(key % 2 == 0){ System.out.println("To delete key " + key); it.remove(); System.out.println("The key " + + key + " was deleted");}}

這種遍歷是OK的
分析上述原因,如果大家理解了List的遍歷刪除,那麼感覺HashMap的遍歷刪除是不是有類似之處啊。下面就分析一下原因:
如果查詢源代碼以上的三種的刪除方式都是通過調用HashMap.removeEntryForKey方法來實現刪除key的操作。
在removeEntryForKey方法內知識一場了key modCount就會執行一次自增操作,此時modCount就與expectedModCOunt不一致了
,上面三種remove實現中,只有第三種iterator的remove方法在調用完removeEntryForKey方法後同步了expectedModCount值與
modCount相同,所以iterator方式不會拋出異常。最後希望大家遇到問題到查詢源代碼,它會給你最好的解釋!

② java里增強for循環【for(String a : arrayList)】裡面可以修改數據嗎

java里增強for循環【for(String a:arrayList)】裡面可以修改數據,但是不能刪除數據,如下例子:


修改集合:

importjava.util.ArrayList;
importjava.util.List;


publicclassTestA{

publicstaticvoidmain(String[]args){
//集合
List<String>arrayList=newArrayList<String>();
//存放元素
arrayList.add("hello");
arrayList.add("ninghao");
arrayList.add("bye");
//集合標量
intindex=0;
//遍歷集合
for(Stringa:arrayList){
//輸出集合對象
System.out.println(a);
//修改集合對象
arrayList.set(index,"hi");
//標量加一
index++;
}
//輸出集合
System.out.println(arrayList);
}
}

結果:
hello
ninghao
bye
[hi,hi,hi]

刪除集合元素:

importjava.util.ArrayList;
importjava.util.List;


publicclassTestA{

publicstaticvoidmain(String[]args){
//集合
List<String>arrayList=newArrayList<String>();
//存放元素
arrayList.add("hello");
arrayList.add("ninghao");
arrayList.add("bye");
//集合標量
intindex=0;
//遍歷集合
for(Stringa:arrayList){
//輸出集合對象
System.out.println(a);
//刪除元素
arrayList.remove(index);

//標量加一
index++;
}
//輸出集合
System.out.println(arrayList);
}
}
結果:
hello
Exceptioninthread"main"java.util.
atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
atjava.util.AbstractList$Itr.next(AbstractList.java:343)
atapp.TestA.main(TestA.java:19)

由以上例子可以看出,增強for循環,在循環里可以修改集合元素,但是不能刪除集合元素。

③ 增強for循環怎麼刪除集合的元素

一個循環迭代,跟集合的增刪改沒什麼關系。修改集合不是for去做的。
for只管循環迭代,你在循環里邊修改集合,改變集合的長度,順序對循環都有影響

④ 增強for循環的內部也就是調用iteratoer實現的嗎請舉出點證據。不要只回答是或者不是。

1.首先增強for循環和iterator遍歷的效果是一樣的,也就說增強for循環的內部也就是調用iteratoer實現的,

但是增強for循環有些缺點,例如不能在增強循環里動態的刪除集合內容。不能獲取下標等。
2.ArrayList由於使用數組實現,因此下標明確,最好使用普通循環。
3.而對於LinkedList 由於獲取一個元素,要從頭開始向後找,因此建議使用增強for循環,也就是iterator。

⑤ JAVA增強for循環為什麼不能增刪集合

foreach循環規定,只能查看集合元素.不能對齊進行增刪改.如果你要增刪改,必須事後立馬跳出foreach循環.
這里說的foreach即使增強for循環!

⑥ 增強for循環和傳統for循環有什麼區別

增強for循環亦為高級for循環。

增強for循環內部是使用的Iterator來遍歷的,只能遍歷數組和實現了Iterable介面的集合。優點是寫法簡便,無需獲得數組、集合長度,也無需根據索引來訪問元素。缺點是不能在循環里動態的刪除元素和獲取元素下標。

任何的增強for循環都可以改寫為普通for循環。遍歷集合所有元素的話用增強for循環更加簡潔,如果是復雜的循環,還是用for循環比較好,for循環功支持索引取元素,可以使用下標來控制位置。

高級for有一個局限性,必須有被遍歷的目標。
建議在遍歷數組的時候,還是希望使用傳統for,因為傳統for可以定義角標。
凡是支持迭代器的都支持高級for

.而對於 LinkedList 由於獲取一個元素,要從頭開始向後找,因此建議使用 增強for循環,也就是iterator。

下面用一個例子說明這點:

代碼一

(List<Integer>lst)

  • {

  • for(Integerx:lst)

  • if(x%2==0)

  • lst.remove(x);

  • System.out.println(lst);

  • }

  • public static void removeEvensVer2(List<Integer> lst)

  • {

  • for (Integer x : lst)

  • if (x % 2 == 0)

  • lst.remove(x);


  • System.out.println(lst);

  • }


  • 代碼二

  • (List<Integer>lst)

  • {

  • Iterator<Integer>itr=lst.iterator();

  • while(itr.hasNext())

  • if(itr.next()%2==0)

  • itr.remove();

  • System.out.println(lst);

  • }

  • public static void removeEvensVer3(List<Integer> lst)

  • {

  • Iterator<Integer> itr = lst.iterator();

  • while (itr.hasNext())

  • if (itr.next() % 2 == 0)

  • itr.remove();


  • System.out.println(lst);

  • }


  • 代碼一在運行時拋出異常,代碼二正常

  • 原因分析:因為增強的for循環內部就是調用iterator實現的,在遍歷的時候就將list轉化為了迭代器,當迭代器被創建之後,如果從結構上對列表修改除非通過迭代器自身的remove、add方法,其他任何時間任何方式的修改,迭代器都會拋出異常。