一种较为隐蔽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: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...
随机推荐
- 是时候抛弃web.xml了?
你是否再为配置文件web.xml容易出错而烦恼?是否为web.xml文件存放位置而不知所措?是否为web.xml为什么要这样配?怎么才能更好的配置web.xml而烦恼?那么一种新的方式出现了: spr ...
- 如何修改Web.Config里面的值
0.先添加 <add key="MAXNUM" value="6" /> 1.读取值 string maxNum = ConfigurationMa ...
- SpringMVC框架的多表查询和增删查改
必须声明本文章==>http://www.cnblogs.com/zhu520/p/7883268.html 一: 1):我的运行环境 我使用myeclipse(你也可以使用eclipse),t ...
- java设计模式--事件监听器模式和观察者模式
监听器模式:事件源经过事件的封装传给监听器,当事件源触发事件后,监听器接收到事件对象可以回调事件的方法 观察者模式:观察者(Observer)相当于事件监听者,被观察者(Observable)相当于事 ...
- ethercat主站控制软件TwinCAT的安装
TwinCAT软件系统是基于PC兼容机的自己主动化系统,全称是"The Windows Control and Automation Technology".它把不论什么PC兼容机 ...
- 获取个人借阅信息---图书馆client
在上一篇利用jsoup解析个人信息----图书馆client,获得个人基本信息后.便有了进一步的需求:获取当前借阅的具体信息 获取的方法还是一样的.利用jsoup解析借阅信息页面,获得所需数据,封装成 ...
- 57.C++处理转义字符
#include <iostream> #include <string> #include <cstdlib> using namespace std; void ...
- spark源码阅读
根据spark2.2的编译顺序来确定源码阅读顺序,只阅读核心的基本部分. 1.common目录 ①Tags②Sketch③Networking④Shuffle Streaming Service⑤Un ...
- 多行文本溢出显示...的方法(-webkit-line-clamp)
限制在一个块元素显示的文本的行数. -webkit-line-clamp 是一个 不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中. 为了实现该 ...
- CMDB学习之二数据采集
首先也要调用插件的方式,来写采集数据插件,在src目录下创建一个插件 plugins ,然后在plugins下创建disk.py ,memory.py, network.py等等 src plugin ...