一种较为隐蔽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: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...
随机推荐
- react-native使用androidstudio时,安卓模拟器reload菜单界面显示快捷键ctrl+M;
react-native使用androidstudio时,安卓模拟器reload菜单界面显示快捷键ctrl+M:
- BZOJ2636: crisis(可持久化线段树)
传送门: 解题思路: 题目描述是一大坑点,cancel后面是直接加ask或者redo的. 那么就可以愉快地可持久化了. 注意需要支持区间修改,那么就只需要在再次更新这个点的时候将标记储存在新的儿子中. ...
- mysql源码安装(包括5.5和5.7)
1.mysql5.5源码安装 yum install -y cmake ncurses-devel ncurses cd /usr/src wget -c https://cdn.mysql.com/ ...
- 紫书 习题 10-19 UVa 10868 (物理动能定理)
这道题看起来很长,而实际上就是考物理 可以用动能定理来算出末速度. 同时注意要特判绳子比桥还长的情况. #include<cstdio> #include<cmath> #de ...
- jquery正则匹配URL地址
JQuery代码: var regexp = /((http|ftp|https|file):\/\/([\w\-]+\.)+[\w\-]+(\/[\w\u4e00-\u9fa5\-\.\/?\@\% ...
- javascript——对象
分类 JavaScript对象分类: 内置对象:由ECMAScript规范定义的对象或类,例如:数组.函数.日期(Date()).正则表达式 宿主对象:是由js解释器所嵌入的宿主环境(比如Web浏览器 ...
- FZU 1968 Twinkling lights III
Twinkling lights III Time Limit: 8000ms Memory Limit: 131072KB This problem will be judged on FZU. O ...
- 【Swift初见】Swift数组(二)
在苹果的开发文档中对Array还提供了其它的操作算法: 1.Sort函数: 对数组进行排序.依据指定的排序规则,看以下的代码: var array = [2, 3, 4, 5] array.sort{ ...
- 停止复制代理后AWT缓存组的行为
AWT缓存组中尽管大多数时候数据是从TimesTen到Oracle,但也存在数据从Oracle到TimesTen的情形. 数据从TimesTen下沉到Oracle依靠复制代理,数据从Oracle到Ti ...
- 流媒体技术 rtp/rtcp/rtsp资料精华!
流媒体技术 rtp/rtcp/rtsp资料精华! 流媒体技术 流媒体是指在网络中使用流式(Sreaming)传输技术进行传输的连续时基媒体.如音频数据流或视频数据流,而不是一种新的媒体.流媒体技 ...