java遍历集合删除特定元素的 java.util.ConcurrentModificationException异常

来源:互联网 发布:知世与艾利欧 艾知 编辑:程序博客网 时间:2024/04/30 00:58

看一段代码:

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同样自增。也就不会抛出异常。

 

0 0
原创粉丝点击