看一段代码:
for (SecurityPsn psn : psnList) {
if(StringUtils.isBlank(psn.getCertCode())){
psnList.remove(psn);
}
}
该代码会抛出java.util.ConcurrentModificationException异常
正确代码为:
Iterator<SecurityPsn> iter = psnList.iterator();
while (iter.hasNext()) {
SecurityPsn psn = iter.next();
if (StringUtils.isBlank(psn.getCertCode())) {
iter.remove();
}
}
解决办法为:如果不是Iterator迭代方式,则修改迭代方式为Iterator()方式,采用iterator.remove();而不直接通过map.remove();
原因:当修改的个数跟期望修改的个数不相等时抛出此异常。
如果改成:
for (int i=0;i<psnList.size();i++ ) {
if(StringUtils.isBlank(psnList.get(i).getCertCode())){
psnList.remove(psn);
}
}
虽然不报上述错误,但结果不准确,且最后一个下标可能会越界。
因为集合的大小是动态变化的,当你删除一个元素之后,元素中的序号又重新排列,原来第二个应该删除的元素现在排在了第一个元素的位置,真正删除的却是第三个元素,依次类推,删除的是第一个、第三个、第五个,所以第二种正确的做法为:
for (int i=0;i<psnList.size();i++ ) {
if(StringUtils.isBlank(psnList.get(i).getCertCode())){
psnList.remove(psnList.get(i));
i--;
}
}
源码分析:
final Entry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException(); // 抛出异常
Entry<K, V> e = current = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
return e;
}
...
查看remove()方法代码如下:
/** * Removes the mapping for the specified key from this map if present. * * @param key key whose mapping is to be removed from the map * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); } /** * Removes and returns the entry associated with the specified key * in the HashMap. Returns null if the HashMap contains no mapping * for this key. */ final Entry<K,V> removeEntryForKey(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; while (e != null) { Entry<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
发现,其中有modCount++操作。
modCount表示修改的次数,而并没有改变其exceptedmodCount;
接下来看看iterator.remove()方法:(java.util.Hashtable.Enumerator.remove())
public void remove() {
if (!iterator)
throw new UnsupportedOperationException();
if (lastReturned == null)
throw new IllegalStateException("Hashtable Enumerator");
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
synchronized(Hashtable.this) {
Entry[] tab = Hashtable.this.table;
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if (e == lastReturned) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
lastReturned = null;
return;
}
}
throw new ConcurrentModificationException();
}
}
}
而此删除元素的方法,将modCount自增的同时将exceptedModCount同样自增。也就不会抛出异常。