HashMap 为什么不能遍历的同时进行增删操作?
↓推荐关注↓
转自:你呀不牛, juejin.cn/post/7114669787870920734
foreach 循环?
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 (Integer
var: 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()) {
Integer
var = it.next();
}
}
}
HashMap 遍历集合并对集合元素进行 remove、put、add
1、现象
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);
}
}
}
这就是验证了上面说的 put 操作可能会抛出 java.util.ConcurrentModificationException 异常。
但是有疑问了,我们上面说过 foreach 循环就是通过迭代器进行的遍历啊?为什么到这里是不可以了呢?
这里其实很简单,原因是我们的遍历操作底层确实是通过迭代器进行的,但是我们的 remove 等操作是通过直接操作 map 进行的,如上例子:map.put(4, "AA"); //这里实际还是直接对集合进行的操作,而不是通过迭代器进行操作。所以依然会存在 ConcurrentModificationException 异常问题。
2、细究底层原理
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进行同步
}
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;
else
p.next = node.next;
++modCount; //----这里对modCount进行了自增,可能会导致后面与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();
}
}
}
}
- EOF -
1、大厂都病了!
关注「程序员的那些事」加星标,不错过圈内事
点赞和在看就是最大的支持❤️
微信扫码关注该文公众号作者
戳这里提交新闻线索和高质量文章给我们。
来源: qq
点击查看作者最近其他文章