今天在翻看HDFS中FSImage初始化部分时,其中有段代码是这样的:
for (URI dirName : fsNameDirs) {
boolean isAlsoEdits = false;
for (URI editsDirName : fsEditsDirs) {
if (editsDirName.compareTo(dirName) == 0) {
isAlsoEdits = true;
fsEditsDirs.remove(editsDirName);
break;
}
}
}
根据以往经验,这段代码可能会有ConcurrentModificationException发生。在向他们指出这个问题前,我写了简单几句测试代码来提前验证下。
代码一:
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
for (String str : list) {
if (str.equals("a")) {
list.remove(str);
}
}
System.out.println(list);
代码一的结果如预期抛出异常。因为在迭代过程中再去删除元素,会造成迭代索引有问题。于是我又随手修改了下判断条件,删除list不同位置的元素。大家看下面这个例子,它的结果应该是什么?
代码二:
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
for (String str : list) {
if (str.equals("b")) {
list.remove(str);
}
}
System.out.println(list);
代码二的运行结果是正常的:[a, c]。
这让我比较迷惑了。接着试了几次后发现,在一个list中,只有删除倒数第二个元素时是正常的,删除其它位置都会有异常抛出。于是我翻看了AbstractList中的迭代实现,主体是下面这三段代码
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
E next = get(cursor++);
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
cursor标示着当前list的索引,不断地与list size比对。如果hasNext返回true,会紧接着执行next方法,在next方法中检查当前list有没有被修改过。
在list迭代过程中,如果删除一个元素,那么size就减一,hasNext提前结束,迭代不会到达list的最后一个元素。也就是说,如果在迭代到list倒数第二个元素时删除此元素,接下来的hasNext会返回false,迭代结束,不会进入next方法中做检查,也就不会出什么问题。而除此之外的其它情况下,hasNext都是true,接下来的next方法检查时会产生异常。
问题让我很疑惑,但分析后的原理很简单。惟一感觉与平时想法不一样的地方是它对hasNext的判断条件有些奇怪。它没有以cursor小于list size来判断,而是取它俩是否相等,在cursor超过size时,又在从list中get元素时施以IndexOutOfBound的弥补。
分享到:
相关推荐
NULL 博文链接:https://langyu.iteye.com/blog/1167581
09.java基础拾遗--类的加载和对象的构造过程.mp4
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
java知识拾遗--三大框架的技术起源.pdfjava知识拾遗--三大框架的技术起源.pdf
Struts、Hibernate和Spring是我们Java开发中的常用的框架,他们分别针对不同的应用场景给出最合适的解决方案。但你是否知道,这些知名框架最初是怎样产生的?
java知识拾遗--三大框架的技术起源.docxjava知识拾遗--三大框架的技术起源.docx
10.java基础拾遗--匿名内部类的应用--实现scala中的集合map方法.mp4
11.java基础拾遗--匿名内部类语法详解.mp4
Java语言拾遗 │ │ └─util 工具类 │ └─mq 消息队列 │ └─kafka └─resources 消息队列源码会作专题研究 关于消息队列使用参考另一个库:https://github.com/GitJavaProgramming/springboot_mybatis 参考...
17. 拾遗物品登记表.pdf
大家好,这是 [C#.NET 拾遗补漏] 系列的第 07 篇文章。 在 C# 中,大多数方法都是通过 return 语句立即把程序的控制权交回给调用者,同时也会把方法内的本地资源释放掉。而包含 yield 语句的方法则允许在依次返回多...
绍mplayer安装过程与拾遗
洛中访袁拾遗不遇古诗阅读答案.docx
拾遗·椰雕.css
Java学习笔记 入门准备 接触物件 物件向导 资源管理 物件容器 输入输出 執行緒 反射 metadata 资料库 拾遗补缺 视窗程式 参考资料
小学语文教学点滴拾遗
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
access代码技巧拾遗 一、在窗体上加按钮,单击后删除窗体上的照片―― 二、在窗体上加文本框,对窗体上的列表框内的数据进行计数―