一种较为隐蔽ConcurrentModificationException情形
ConcurrentModificationException是遍历过程中修改list而抛出的错误。就像前面分析的,单线程时这种错误主要是因为使用forEach造成:遍历一个拷贝,修改原始list,造成的。简单的大家都知道,这里要说一种比较隐蔽的出错方式:
1 public class ExceptionTest{
2
3 private List<String> list = new ArrayList<>();
4
5 public ExceptionTest(){
6 for(int i=0;i<9;i++){
7 list.add("string"+i);
8 }
9 }
10
11 public void throwExceptions(){
12 List<List<String>> listList = new ArrayList<>();
13 listList.add(list.subList(0,3));
14 listList.add(list.subList(3,6));
15 listList.add(list.subList(6,8));
16 Iterator<List<String>> it1 = listList.iterator();
17 while(it1.hasNext()){
18 List<String> l = it1.next();
19 Iterator<String> it = l.iterator();
20 while(it.hasNext()){
21 String str = it.next();
22 if(str.endsWith(("5"))){
23 it.remove();
24 }
25 }
26 }
27 }
28 }
运行上面的代码还是会出错,虽然两层循环都用来Iterator。如果不仔细看很难发现这其中的原因。当你调试你会发现,删除以5结尾的字符串的时候,listList中的第一个子list会报错,而不是正在做修改的第二个子list。所以这个错误的来源不是两个遍历的本事,而是listList的初始化方式,可以看到13到16行,每个子列表使用的是list的subList方法。进一步查看subList代码可以发现。这个方法其实并未新建list而是返回了原理list的一个视图(其实索引):
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
所以在修改第二个子list的时候回引起父列表(list)状态发生改变,虽然两层遍历看起来是正常的,但是他们却是在遍历和修改同一个list,因此会抛出ConcurrentModificationException异常。
总结:有时候的异常并不是因为当前的步骤引起的,原因有可能来自于之前的某一步骤。
一种较为隐蔽ConcurrentModificationException情形的更多相关文章
- [转]Javascript中几种较为流行的继承方式
出处:http://www.jianshu.com/p/a6c005228a75 开篇 从'严格'意义上说,javascript并不是一门真正的面向对象语言.这种说法原因一般都是觉得javascrip ...
- auto_ptr解析
auto_ptr是当前C++标准库中提供的一种智能指针,或许相对于boost库提供的一系列眼花缭乱的智能指针, 或许相对于Loki中那个无所不包的智能指针,这个不怎么智能的智能指针难免会黯然失色.诚然 ...
- c++11 auto_ptr介绍
在代码里面看到了auto_ptr这个东西,正好以前一哥们曾经问过我这个问题..所以特意去搜了搜帖子,学习学习 http://www.cnblogs.com/gaoxianzhi/p/4451803.h ...
- auto_ptr, which can release the space automatically
C++的auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理. 使用std::auto_ptr,要#include <memory>.[1] 中文名 自动指针 外 ...
- c++智能指针《一》 auto_ptr
转载http://www.cnblogs.com/gnagwang/archive/2010/11/19/1881811.html C++的auto_ptr auto_ptr所做的事情,就是动态分配对 ...
- C++智能指针--auto_ptr指针
auto_ptr是C++标准库提供的类模板,头文件<memory>,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同一时候被分给两个拥有者.当 ...
- .NET中的缓存
构建高性能的应用程序的非常重要一项就是使用缓存.使用缓存可以避免重新从读取服务器端读取数据,节省数据从客户端到服务器间往返的时间,同时也减轻了服务器数据存取的压力.如果客户端非常频繁地读取服务器上的数 ...
- 测试MySQL锁的问题
测试MySQL锁的问题 目录 测试MySQL锁的问题 1 Record Lock 2 Next-Key Lock 2 死锁测试 InnoDB支持三种行锁: Record Lock:单个行记录上面的锁 ...
- PostgreSQL EXPLAIN执行计划学习--多表连接几种Join方式比较
转了一部分.稍后再修改. 三种多表Join的算法: 一. NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...
随机推荐
- SQL中union union all 和in的查询效率问题
UNION用的比较多union all是直接连接,取到得是所有值,记录可能有重复 union 是取唯一值,记录没有重复 1.UNION 的语法如下: [SQL 语句 1] UNION [SQL 语句 ...
- 现实人脸识别性别之路----弄清楚train_test_split函数
'''train_test_split(trian_data,trian_target,test_size,random_state)各个参数表示的意义:trian_data表示被划分的样本特征集tr ...
- POJ——T3160 Father Christmas flymouse
Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 3496 Accepted: 1191 缩点,然后每个新点跑一边SPFA ...
- 洛谷 P3040 [USACO12JAN]贝尔分享Bale Share
P3040 [USACO12JAN]贝尔分享Bale Share 题目描述 Farmer John has just received a new shipment of N (1 <= N & ...
- Maven实战(八)---模块划分
为了防止传递依赖,我们各个模块之间尽量用直接依赖的方式.本篇文章介绍多模块化开发.我们做过Maven项目的都知道.我们的项目一般都是分模块的,每一个模块都会相应着一个POM.xml文件,它们之间通过继 ...
- Android插件化(二):使用DexClassLoader动态载入assets中的apk
Android插件化(二):使用DexClassLoader动态载入assets中的apk 简单介绍 上一篇博客讲到.我们能够使用MultiDex.java载入离线的apk文件.须要注意的是,apk中 ...
- CCNA Cloud CLDFND 210-451 QUIZ: Server Virtualization
Author:海峰 http://weibo.com/344736086 http://yanheven.github.io/ http://blog.csdn.net/yanheven1 1.Whi ...
- 消灭星星的数组高效率算法(c++代码,控制台程序)
#include <iostream> using namespace std; #define ROW 12 #define COL 10 class Star { public: en ...
- .Net写的比较清晰的接口
尼玛,隔行如隔山. .Net真操蛋. /// <summary> /// 加入群 /// </summary> /// <returns></returns& ...
- Ajax的跨域问题分析
一.Ajax的跨域问题 Ajax是利用javascript内置XMLHttpRequest对象来进行传输的,所以它依赖于XMLHttpRequest对象,而XMLHttpRequest对象却有很多的限 ...