HashMap 為什么不能一邊遍歷一遍刪除
點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

foreach 循環(huán)?
public class HashMapIteratorDemo {String[] arr = {"aa","bb","cc"};public void test1() {for (String str: arr) {}}}

public class HashMapIteratorDemo2 {String[] arr = {"aa","bb","cc"};public void test1() {for (int i = 0; i < arr.length; i++) {String str = arr[i];}}}

public class HashMapIteratorDemo3 {List < Integer > list = new ArrayList < > ();public void test1() {list.add(1);list.add(2);list.add(3);for (Integervar: list) {}}}
public class HashMapIteratorDemo4 {List < Integer > list = new ArrayList < > ();public void test1() {list.add(1);list.add(2);list.add(3);Iterator < Integer > it = list.iterator();while (it.hasNext()) {Integervar = it.next();}}}


HashMap 遍歷集合并對(duì)集合元素進(jìn)行 remove、put、add
1、現(xiàn)象
public class HashMapIteratorDemo5 {public static void main(String[] args) {Map < Integer, String > map = new HashMap < > ();map.put(1, "aa");map.put(2, "bb");map.put(3, "cc");for (Map.Entry < Integer, String > entry: map.entrySet()) {int k = entry.getKey();String v = entry.getValue();System.out.println(k + " = " + v);}}}

public class HashMapIteratorDemo5 {public static void main(String[] args) {Map < Integer, String > map = new HashMap < > ();map.put(1, "aa");map.put(2, "bb");map.put(3, "cc");for (Map.Entry < Integer, String > entry: map.entrySet()) {int k = entry.getKey();if (k == 1) {map.put(1, "AA");}String v = entry.getValue();System.out.println(k + " = " + v);}}}


public class HashMapIteratorDemo5 {public static void main(String[] args) {Map < Integer, String > map = new HashMap < > ();map.put(1, "aa");map.put(2, "bb");map.put(3, "cc");for (Map.Entry < Integer, String > entry: map.entrySet()) {int k = entry.getKey();if (k == 1) {map.put(4, "AA");}String v = entry.getValue();System.out.println(k + " = " + v);}}}

這就是驗(yàn)證了上面說的 put 操作可能會(huì)拋出 java.util.ConcurrentModificationException 異常。
但是有疑問了,我們上面說過 foreach 循環(huán)就是通過迭代器進(jìn)行的遍歷啊?為什么到這里是不可以了呢?
這里其實(shí)很簡(jiǎn)單,原因是我們的遍歷操作底層確實(shí)是通過迭代器進(jìn)行的,但是我們的 remove 等操作是通過直接操作 map 進(jìn)行的,如上例子:map.put(4, "AA"); //這里實(shí)際還是直接對(duì)集合進(jìn)行的操作,而不是通過迭代器進(jìn)行操作。所以依然會(huì)存在 ConcurrentModificationException 異常問題。
2、細(xì)究底層原理
final Node < K, V > nextNode() {Node < K, V > [] t;Node < K, V > e = next;if (modCount != expectedModCount)throw new ConcurrentModificationException();if (e == null)throw new NoSuchElementException();if ((next = (current = e).next) == null && (t = table) != null) {do {} while (index < t.length && (next = t[index++]) == null);}return e;}

public V remove(Object key) {Node < K, V > e;return (e = removeNode(hash(key), key, null, false, true)) == null ?null : e.value;}
public final boolean remove(Object key) {return removeNode(hash(key), key, null, false, true) != null;}
public final boolean remove(Object o) {if (o instanceof Map.Entry) {Map.Entry << ? , ? > e = (Map.Entry << ? , ? > ) o;Object key = e.getKey();Object value = e.getValue();return removeNode(hash(key), key, value, true, true) != null;}return false;}
public final void remove() {Node < K, V > p = current;if (p == null)throw new IllegalStateException();if (modCount != expectedModCount)throw new ConcurrentModificationException();current = null;K key = p.key;removeNode(hash(key), key, null, false, false);expectedModCount = modCount; //--這里將expectedModCount 與modCount進(jìn)行同步}
final Node < K, V > removeNode(int hash, Object key, Object value,boolean matchValue, boolean movable) {Node < K, V > [] tab;Node < K, V > p;int n, index;if ((tab = table) != null && (n = tab.length) > 0 &&...if (node != null && (!matchValue || (v = node.value) == value ||(value != null && value.equals(v)))) {if (node instanceof TreeNode)((TreeNode < K, V > ) node).removeTreeNode(this, tab, movable);else if (node == p)tab[index] = node.next;elsep.next = node.next;++modCount; //----這里對(duì)modCount進(jìn)行了自增,可能會(huì)導(dǎo)致后面與expectedModCount不一致--size;afterNodeRemoval(node);return node;}}return null;}
public class HashMapIteratorDemo5 {public static void main(String[] args) {Map < Integer, String > map = new HashMap < > ();map.put(1, "aa");map.put(2, "bb");map.put(3, "cc");Iterator < Map.Entry < Integer, String >> it = map.entrySet().iterator();while (it.hasNext()) {Map.Entry < Integer, String > entry = it.next();int key = entry.getKey();if (key == 1) {it.remove();}}}}
轉(zhuǎn)自:你呀不牛, 鏈接:juejin.cn/post/7114669787870920734
往 期 推 薦
3、互聯(lián)網(wǎng)人為什么學(xué)不會(huì)擺爛
4、為什么國(guó)外JetBrains做 IDE 就可以養(yǎng)活自己,國(guó)內(nèi)不行?區(qū)別在哪?
點(diǎn)分享
點(diǎn)收藏
點(diǎn)點(diǎn)贊
點(diǎn)在看
評(píng)論
圖片
表情





