首先通过一个案例来引出要讨论的话题:
public class User { private Integer uid; private String uname; public User() { } public User(Integer uid, String uname) { this.uid = uid; this.uname = uname; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } }
public class CollectionModifyExceptionTest { public static void main(String[] args) { /*创建一个集合*/ Collection<User> users = new ArrayList<User>(); /*往集合中添加数据*/ users.add(new User(1, "习近平")); users.add(new User(1, "李克强")); users.add(new User(1, "王岐山")); /*获取迭代器*/ Iterator<User> itrUsers = users.iterator(); /*遍历*/ while (itrUsers.hasNext()) { User user = (User) itrUsers.next(); if ("王岐山".equals(user.getUname())) { users.remove(user); } else { System.out.println(user); } } } }
程序运行的结果:
为什么会报错呢?
原因:不可以对iterator相关的地方做添加或删除操作。
我们来看看iterator()方法:
public Iterator<E> iterator() { return new Itr(); }
在new Itr()时有一个关键操作:
/** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount;
在来看看List集合中的remove()方法:
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }
在看一下iterator.next()操作的源码:
public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
从上述源码中可以看出:iterator 时 将expectedModCount = modCount 在remove()时 modCount++ 导致next()时抛出异常:
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
一旦添加或删除元素后,modCount,expectedModCount这两个值就会不一样,当next时就会报错。
解决方案一:
再定义一个集合,在遍历过程中,把要删除的元素,添加到该集合中,迭代完成之后,直接删除这个集合中的内容即可。
解决方法二:
使用java5中的可同步集合类:CopyOnWriteArrayList<T>
修改代码如下:
public class CollectionModifyExceptionTest { public static void main(String[] args) { /*创建一个集合*/ //Collection<User> users = new ArrayList<User>(); Collection<User> users = new CopyOnWriteArrayList<User>(); /*往集合中添加数据*/ users.add(new User(1, "习近平")); users.add(new User(1, "李克强")); users.add(new User(1, "王岐山")); /*获取迭代器*/ Iterator<User> itrUsers = users.iterator(); /*遍历*/ while (itrUsers.hasNext()) { User user = (User) itrUsers.next(); if ("王岐山".equals(user.getUname())) { users.remove(user); } else { System.out.println(user); } } } }