一种较为隐蔽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: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...
随机推荐
- POJ 1671 第二类斯特林数
思路: 递推出来斯特林数 求个和 if(i==j)f[i][j]=1; else f[i][j]=f[i-1][j-1]+f[i-1][j]*j; //By SiriusRen #include &l ...
- MVC页面常用方法
转自:https://www.cnblogs.com/baisoft/p/5839319.html @RenderBody 在Razor引擎中没有了“母版页”,取而代之的是叫做“布局”的页面(_Lay ...
- 昼猫笔记 从此告别复杂代码--JavaScript
昼猫笔记--给你带来不一样的笔记 不止是笔记 更多的是思考 大家好,我是一只来自喵星的前端初学者,由于我们喵星人科技较为落后,昼猫从今天开始带着使命来到地球学习前端知识. 从今天开始,猫猫我就从Jav ...
- XML解析——DOM解析
XML:可扩展性标记语言,主要用来传输和存储数据,相对于HTML的各种标签规范,XML的标签可以让用户根据语义自己进行定义,适用于web传输. JSON和XML的区别: (1).XML定义 扩展标记语 ...
- HTTP请求和响应1:概述
HTTP的报文分为请求报文和响应报文,打开一个web页面后,浏览器将发起一个HTTP请求报文.HTTPserver收到请求后将回送一个响应报文. 报文的基本结构 HTTP的请求和响应报文都由三个部分组 ...
- Python 值传递和引用传递
值传递和引用传递 參考地址:http://www.dataguru.cn/thread-489552-1-1.html python的值传递不会改变传入參数的值,而引用传递传入的是一个地址.有点相似c ...
- 前台ajax验证技术采用正则表达式
var flag1,flag2,flag3,flag4,flag5,flag6=false; function val(obj) { var regBox = { /* regEmail : /^([ ...
- 什么是CSS重置,有些什么作用?
CSS重置是什么? 简单的说就是重置浏览器的CSS默认属性. 为什么要重置它,有什么作用? 因为浏览器的品种很多,每个浏览器的默认样式也是不同的,比如<button>标签,在IE浏览器.F ...
- java接口理解(转载)
今天和同事好好的讨论了java接口的原理和作用,发现原来自己的对接口的理解仅仅是局限在概念的高度抽象上,觉得好像理解了但是不会变化应用其实和没有理解差不多.以前看一个帖子说学习一个东西不管什么时候都要 ...
- host---域名查询
host命令是常用的分析域名查询工具,可以用来测试域名系统工作是否正常. 选项 -a:显示详细的DNS信息: -c<类型>:指定查询类型,默认值为“IN“: -C:查询指定主机的完整的SO ...