Arraylist remove元素

1 篇文章 0 订阅

Arraylist remove元素

用Arraylist 的remove方法删除元素时出现如下异常:

三月 01, 2018 2:41:59 下午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [user] in context with path [/jq] threw exception
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
	at java.util.ArrayList$Itr.next(ArrayList.java:851)
	at com.zjht.action.Add.delete(Add.java:151)
	at com.zjht.action.Add.doGet(Add.java:32)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

我使用for-each 循环,如下代码:

for (User user : userList) {
	if(user.getUserid() == userid){
	userList.remove(user);
	}
}

从异常堆栈可以看出,是ArrayList的迭代器报出的异常,说明通过元素遍历集合时,实际上是使用迭代器进行访问的。

可为什么会产生这个异常呢?打断点单步调试进去发现,是这行代码抛出的异常:

    final void checkForComodification() { 
     
    if (modCount != expectedModCount) 
     
    throw new ConcurrentModificationException(); 
     
    } 

modCount是集合修改的次数,当remove元素的时候就会加1,初始值为集合的大小。迭代器每次取得下一个元素的时候,都会进行判断,比较集合修改的次数和期望修改的次数是否一样,如果不一样,则抛出异常。查看集合的remove方法:

    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; // clear to let GC do its work 
     
    } 

可以看到,删除元素时modCount已经加一,但是expectModCount并没有增加。所以在使用迭代器遍历下一个元素的时候,会抛出异常。那怎么解决这个问题呢?

其实使用迭代器自身的删除方法就没有问题了

Iterator<User> iterator = userList.iterator();
	while(iterator.hasNext()){
		if(iterator.next().getUserid() == userid){
			iterator.remove();
			}
		}

查看迭代器自身的删除方法,果不其然,每次删除之后都会修改expectedModCount为modCount。这样的话就不会抛出异常

    public void remove() { 
     
    if (lastRet < 0) 
     
    throw new IllegalStateException(); 
     
    checkForComodification(); 
     
    try { 
     
    ArrayList.this.remove(lastRet); 
     
    cursor = lastRet; 
     
    lastRet = -1; 
     
    expectedModCount = modCount; 
     
    } catch (IndexOutOfBoundsException ex) { 
     
    throw new ConcurrentModificationException(); 
     
    } 
     
    } 

建议以后操作集合类的元素时,尽量使用迭代器。

可是还有一个地方不明白,modCount和expectedModCount这两个变量究竟是干什么用的?

为什么集合在进行操作时需要修改它?为什么迭代器在获取下一个元素的时候需要判断它们是否一样?

它们存在总是有道理的吧


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值