今天在翻看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
Java知识拾遗:三大框架的技术起源 本篇文章主要讲述了Java开发中三大框架的技术起源,即Struts、Hibernate和Spring框架。这些框架是我们Java开发中的常用的框架,它们分别针对不同的应用场景给出最合适的解决方案...
09.java基础拾遗--类的加载和对象的构造过程.mp4
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
Java开发中的三大框架——Struts、Hibernate和Spring,都是为了解决传统Java Web应用程序中存在的一系列问题而诞生的。这些框架分别针对MVC模式的实现、数据持久化和依赖管理给出了高效且灵活的解决方案。 Struts...
java回顾、知识整理、拾遗、面试_java-review
10.java基础拾遗--匿名内部类的应用--实现scala中的集合map方法.mp4
11.java基础拾遗--匿名内部类语法详解.mp4
读书笔记:算法 并发 函数式编程 java语言拾遗 手写设计模式
Java开发中的三大框架,即Struts、Hibernate和Spring,各自解决了传统Java Web应用程序中的不同问题,提升了开发效率和代码质量。下面将详细讲解这三个框架的技术起源及其核心功能。 首先,Struts框架诞生于解决JSP...
Java语言拾遗 │ │ └─util 工具类 │ └─mq 消息队列 │ └─kafka └─resources 消息队列源码会作专题研究 关于消息队列使用参考另一个库:https://github.com/GitJavaProgramming/springboot_mybatis 参考...
在学习过程中,参考官方文档、权威书籍和在线教程是必不可少的。例如《Thinking in Java》、《Java核心技术卷》以及Oracle的Java教程,都是深入理解Java的好资源。 通过系统地学习这些知识点,你将能够全面掌握Java...
- **数据结构**:`ArrayList` 基于动态数组实现,提供随机访问元素的能力,因此添加或删除元素时需要移动大量的元素。而 `LinkedList` 基于双向链表实现,对于插入和删除操作更加高效,因为只需要修改指针即可。 - *...
《洛中访袁拾遗不遇》这首古诗是唐代诗人孟浩然的作品,它体现了孟浩然在文学创作中的独特艺术风格。诗的主题围绕着拜访友人却未能相遇的失落情感,同时也揭示了对友人遭遇贬谪的同情与不平。 在诗的第一句“洛阳访...
17. 拾遗物品登记表.pdf
在"day03 拾遗"中,特别提到了小数的取模运算。需要注意的是,Java中的小数取模与整数有所不同,可能会导致非预期的结果。例如,12.12%2.2的结果是1.1199,而8.8%2的结果是0。这是因为浮点数的取模运算并不总是精确...
《路边拾遗》是一本由两位非职业摄影师创作的摄影画册,书中不仅收录了他们拍摄的精美照片,更重要的是传达了作者对摄影艺术的理解与感悟。通过这本画册,我们可以深刻理解摄影不仅仅是一种技术活动,更是一种心灵的...
- **自动修改源**:可以在kickstart脚本中添加命令来自动修改源文件,例如使用`sed`或`awk`命令来更新`/etc/apt/sources.list`文件中的源地址。 - **其他定制化需求**:通过编写shell脚本或使用PXE安装工具集提供的...