在遍历 Hashmap 时,Hashmap 在 remove() 和 put() 上的行为不同
Hashmap behaves differently upon remove() and put() while iterating through Hashmap
我试图更好地理解 hashmap,我研究了代码和可能性。当我想到这个时
//HashMap
Map<String, String> myMap = new HashMap<>();
myMap.put("1", "1");
myMap.put("2", "1");
myMap.put("3", "1");
System.out.println("HashMap before iterator: " + myMap);
for(String key : myMap.keySet()){
if(key.equals("3")) {
myMap.put(key + "new", "new3");
myMap.remove("2");
}
};
for(String key : myMap.keySet()){
if(key.equals("3")) {
myMap.put(key + "new", "new3");
break;
}
};
System.out.println("HashMap after iterator: " + myMap);
这个输出是
HashMap before iterator: {1=1, 2=1, 3=1}
HashMap after iterator: {1=1, 3=1, 3new=new3}
hashmap 中的迭代器是快速失败的,那么它如何适应这种变化。在此之后,我开始知道有一个计数器可以检查 hashmap 的大小,并在 next()[ 中大小不匹配时抛出异常=32=].
我不明白的是如何打破循环避免在正确的时刻调用 next() 以跳过检查。我什至看了迭代器HashIterator的代码
我不知道当代码命中 break;
时,hoe 不会调用 next()
为什么这段代码不会抛出错误。
//HashMap
HashMap<String, String> myMap = new HashMap<>();
myMap.put("1", "1");
myMap.put("2", "1");
myMap.put("3", "1");
System.out.println("HashMap before iterator: "+myMap);
for(String key : myMap.keySet()){
if(key.equals("3"))
myMap.remove("2");
};
System.out.println("HashMap after iterator: " + myMap);
for(String key : myMap.keySet()){
if(key.equals("3"))
myMap.put(key + "new", "new3");
};
System.out.println("HashMap after iterator: " + myMap);
请帮助我更好地理解这一点。
嗯,HashIterator
检查 next()
中的 modCount
,但不检查 hasNext()
中的 modCount
:
public final boolean hasNext() {
return next != null;
}
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;
}
由于您要在循环的最后一次迭代中对 HashMap
进行结构更改,因此更改 hasNext()
returns false
和 next()
不再调用。因此也不例外。
请注意,由增强的 for 循环创建的迭代器并不知道您向 Map
添加了一个额外的 Entry
。因此它不会迭代那个额外的 Entry
。快速失败机制只有在迭代器的 next()
方法被调用时才能工作,但如前所述,当您在循环的最后一次迭代中进行更改时不会发生这种情况。
我试图更好地理解 hashmap,我研究了代码和可能性。当我想到这个时
//HashMap
Map<String, String> myMap = new HashMap<>();
myMap.put("1", "1");
myMap.put("2", "1");
myMap.put("3", "1");
System.out.println("HashMap before iterator: " + myMap);
for(String key : myMap.keySet()){
if(key.equals("3")) {
myMap.put(key + "new", "new3");
myMap.remove("2");
}
};
for(String key : myMap.keySet()){
if(key.equals("3")) {
myMap.put(key + "new", "new3");
break;
}
};
System.out.println("HashMap after iterator: " + myMap);
这个输出是
HashMap before iterator: {1=1, 2=1, 3=1}
HashMap after iterator: {1=1, 3=1, 3new=new3}
hashmap 中的迭代器是快速失败的,那么它如何适应这种变化。在此之后,我开始知道有一个计数器可以检查 hashmap 的大小,并在 next()[ 中大小不匹配时抛出异常=32=].
我不明白的是如何打破循环避免在正确的时刻调用 next() 以跳过检查。我什至看了迭代器HashIterator的代码 我不知道当代码命中 break;
时,hoe 不会调用 next()为什么这段代码不会抛出错误。
//HashMap
HashMap<String, String> myMap = new HashMap<>();
myMap.put("1", "1");
myMap.put("2", "1");
myMap.put("3", "1");
System.out.println("HashMap before iterator: "+myMap);
for(String key : myMap.keySet()){
if(key.equals("3"))
myMap.remove("2");
};
System.out.println("HashMap after iterator: " + myMap);
for(String key : myMap.keySet()){
if(key.equals("3"))
myMap.put(key + "new", "new3");
};
System.out.println("HashMap after iterator: " + myMap);
请帮助我更好地理解这一点。
嗯,HashIterator
检查 next()
中的 modCount
,但不检查 hasNext()
中的 modCount
:
public final boolean hasNext() {
return next != null;
}
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;
}
由于您要在循环的最后一次迭代中对 HashMap
进行结构更改,因此更改 hasNext()
returns false
和 next()
不再调用。因此也不例外。
请注意,由增强的 for 循环创建的迭代器并不知道您向 Map
添加了一个额外的 Entry
。因此它不会迭代那个额外的 Entry
。快速失败机制只有在迭代器的 next()
方法被调用时才能工作,但如前所述,当您在循环的最后一次迭代中进行更改时不会发生这种情况。