执行ArrayList的remove(object)方法抛异常?
简介
或许有很多小伙伴都尝试过如下的代码:
ArrayList<Object> list = ...;
for (Object object : list) {
if (条件成立) {
list.remove(object);
}
}
然后会发现抛出java.util.ConcurrentModificationException异常,这是一个并发异常。那么这个到底是什么情况?首先需要介绍一下增强for循环
增强for循环
增强for循环是Java1.5后,Collection实现了Iterator接口后出现的。增强for循环的代码如下
for (Object object : list) {
// 操作
}
其实增强for循环就是使用Iterator迭代器进行迭代的,增强for循环就变成下面这样:
Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
// 操作
}
那么为什么在增强for循环中调用list.remove(object)会出事呢?那么咱们看看ArrayList下的 Iterator的实现类: Itr类
Itr子类
Itr子类是Iterator的实现类,属于ArrayList私有的局部内部类。我截取了Itr类的部分代码,如下:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
...
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
elementData 是ArrayList存放元素的数组,上面代码没有贴出来。
size 是elementData实际存放的容量大小
modCount 记录elementData容量的修改次数
expectedModCount 记录实例化迭代器Itr时,elementData容量的修改次数
注意!:在迭代器中,当执行next方法的时候,会去调用checkForComodification方法,判断elementData 的容量是否被修改过。
然后来看看ArrayList的remove(object)方法,截取部分代码如下:
public boolean remove(Object o) {
for (int index = 0; index < size; index++)
if (找到目标元素) {
fastRemove(index);
return true;
}
return false;
}
private void fastRemove(int index) {
modCount++;
// 移除操作
}
可以发现,调用remove(object)方法时调用了fastRemove方法,在fastRemove方法中执行modCount++ !
现在把文章开头的代码拷下来,再来分析一次:
ArrayList<Object> list = ...;
for (Object object : list) {
if (条件成立) {
list.remove(object);
}
}
当执行了list.remove时,执行modCount++ 。此时迭代器再往下进行迭代,执行了next方法,发现 modCount != expectedModCount,那么则抛出java.util.ConcurrentModificationException异常。 之所以Iterator认为是一个并发异常。是因为你不在迭代器里操作,而是在迭代器外面进行remove操作呀!
难道没有其他解决方案吗?有滴。
解决方案
那么就是使用Itr的 remove方法。Itr子类重写了 remove 方法,这里部分代码:
public void remove() {
...
try {
ArrayList.this.remove(需要删除元素的索引);
...
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
其实很简单,就是remove后,把 expectedModCount 同步一下 modCount 的值,这就解决了。完整代码如下:
ArrayList<Object> list = ...;
Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
总结
本来我还不知道增强for循环是调用Iterator进行迭代的,要不是我debug了一波,我还不知道呐。还是小有收货。
个人博客网址: https://colablog.cn/
如果我的文章帮助到您,可以关注我的微信公众号,第一时间分享文章给您
执行ArrayList的remove(object)方法抛异常?的更多相关文章
- CloudStack的VO在调用setRemoved方法抛异常的原因
今天在开发中发现一个问题,本来想对一个VO对象的removed值赋值,然后去update一下这条记录,一个最简单的set方法,但是在调用时直接抛异常了. 1: public void setRemov ...
- [Guava学习笔记]Basic Utilities: Null, 前置条件, Object方法, 排序, 异常
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3842433.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- ABP在领域事件中异步调用方法抛异常
在领域事件中调用UserRegistrationManager.RegisterAsync抛异常 Call UserRegistrationManager.RegisterAsync() throw ...
- ArrayList调用remove(int index)抛出UnsupportedOperationException问题分析以及解决记录
使用Arrays转数组成为List后,不能调用add(...)和remove(...)方法,此时如果调用就会抛出UnsupportedOperationException异常 原因 其实Arrays. ...
- 抛异常 throw的注意事项
子类覆盖父类只能抛出父类的异常或者子类或者子集注意:如果父类的方法没有抛异常,那么子类覆盖时绝对不能抛. 子类继承父类时,方法抛异常,要么抛父类,要么抛父类下的子类,不能抛父类平级或以上的异常 原因是 ...
- ArrayList调用remove方法需要注意的地方
ArrayList中有remove 方法和 removeAll方法, ArrayList中不仅继承了接口Collection中的remove方法,而且还扩展了remove方法. Collection中 ...
- Java执行main方法,异常为:could not find the main class.program will exit
未解决. Java执行方法,异常为:could not find the main class.program will exitmain 原文地址:http://rogerfederer.iteye ...
- 线程执行synchronized同步代码块时再次重入该锁过程中抛异常,是否会释放锁
一个线程执行synchronized同步代码时,再次重入该锁过程中,如果抛出异常,会释放锁吗? 如果锁的计数器为1,抛出异常,会直接释放锁: 那如果锁的计数器为2,抛出异常,会直接释放锁吗? 来简单测 ...
- java ArrayList的remove()方法的参数为int和Integer的问题
ArrayList的父类List中,有2个remove重载方法: remove(int index) remove(Object o) 假如参数输入为数字类型,到底是删除值等于该数字的对象还是删除索引 ...
随机推荐
- 提高网站访问性能之Tomcat优化
一.前言 tomcat 服务器在JavaEE项目中使用率非常高,所以在生产环境对tomcat的优化也变得非常重要了,对于tomcat的优化,主要是从2个方面入手,一是tomcat本身的配置,另一个是t ...
- LiveCharts 提示框(DataTooltip)百分比一直为0.00%解决办法
LiveCharts 提示框(DataTooltip)百分比一直为0.00%解决办法 问题描述:在使用LiveCharts 开源图标库的时候,使用CartesianChart类图表,当Series为L ...
- JVM内存结构详解
从java编程语言说起... 1. Java编程语言简介 1.1 编程语言概述 系统级和应用级 系统级:C,C++,go,erlang 应用级:C#,Java,Python,Perl,Ruby,php ...
- @bzoj - 5104@ Fib数列
目录 @description@ @solution@ @accepted code@ @details@ @description@ Fib数列为1,1,2,3,5,8... 求在Mod10^9+9 ...
- 开启PG的归档模式
目录 开启PG的归档模式 1.查看pg的数据目录 2.查看pg的归档情况 3.查看归档的模式和位置 4.建立归档目录 5.配置归档参数 6.重启pg 7.查看&&切换归档日志 8.查看 ...
- ca75a_c++_标准IO库-利用流对象把文件内容读取到向量-操作文件
/*ca75a_c++_标准IO库习题练习习题8.3,8.4,8.6习题8.9.8.10 ifstream inFile(fileName.c_str());1>d:\users\txwtech ...
- 一起玩转微服务(10)——spring boot介绍
对于Spring,相信大家都非常熟悉,从出现开始,一直是企业级开发的主流.但是随着软件的发展和应用开发的不断演化,它的一些缺点也逐渐胡暴露了出来,下面,我们就一起看一下Spring的发展历程并且认识一 ...
- JavaWeb网上图书商城完整项目--day02-5.ajax校验功能之服务器端三层实现
regist.jsp页面中有异步请求服务器来对表单进行校验: l 校验登录名是否已注册过: l 校验Email是否已注册过: l 校验验证码是否正确. 这说明在UserServlet中需要提供相 ...
- 一个工作了四年的java程序员的心得体会
年底了,该给自己写点总结了!从毕业到现在已经快4年啦,一直在Java的WEB开发行业混迹.我不是牛人,但是自我感觉还算是个合格的程序员,有必要写下自己将近4年来的经历,给自我以提示,给刚入行的朋友提供 ...
- SSH网上商城四
第29课:10-SSH网上商城:购物模块的实体的封装 1.现在我们要实现购物车的模块,当用户在点击 加入购物车按钮的时候需要跳转到 上面我们需要对购物车的对象进行封装 上面一个商品就对应一个记录项,购 ...