Iterator、Iteratable与ListIterator
- Iteratable:
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
- Iteratable接口提供了iterator()方法。
- Collection接口继承了Iteratable,由实现Collection的ArrayList、Hashset等来实现方法。
Iterator:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
- Iterator接口在ArrayList、LinkedList等类中都有内部类实现
- Iterator接口的不当使用会导致抛出ConcurrentModificationException:
List<String> famousList = new ArrayList<>();
famousList.add("Sheldon");
famousList.add("Sherlock");
famousList.add("Batman");
famousList.add("Optimus Prime");
for (String famous :
famousList) {
famousList.remove(famous);
}
上面的代码之所以会抛出ConcurrentModificationException异常的原因:
- 增强for循环其实在编译生成字节码后会发现,就是转化为通过调用iterator的hasNext()、next()函数来遍历集合,查看ArrayList的iterator的实现代码:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
从以上代码可知,当调用next()函数的时候,会先调用checkForComodification函数来检查集合的modCount与expectedModCount是否相等,若不相等则抛出错误。来到这里就能知道,在使用iterator遍历集合的时候,使用集合的remove、add等函数,就会导致modCount和expectedModCount不一致,从而导致异常抛出。
- 正确的做法:
Iterator<String> iterator = famousList.iterator();
for (;iterator.hasNext();){
String famous=iterator.next();
System.out.println(famous);
if ("Batman".equals(famous)){
iterator.remove();
break;
}
}
System.out.println(famousList.size());
或者:
for (int i = 0; i < famousList.size(); i++) {
System.out.println(famousList.get(i));
if ("Batman".equals(famousList.get(i))){
famousList.remove(famousList.get(i));
break;
}
}
System.out.println(famousList.size());
- ListIterator:
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
//判断cursor前是否有元素
boolean hasPrevious();
//获得cursor前一个元素,并且cursor后退一位
E previous();
//返回cursor元素的index
int nextIndex();
//返回cursor前一个元素的index
int previousIndex();
void remove();
//更新上一次调用next、previous返回的元素,也就是iterator最后一次操作的元素,没有调用next、previous前调用的话会抛出IllegalStateExceptiony异常
void set(E e);
//向cursor前插入元素
void add(E e);
}
- ListIterator由实现List接口的集合类通过以下两种方法返回:
public ListIterator<E> listIterator() {
return new ListItr(0);
}
//返回指定cursor位置的listIterator
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
相比Iterator,多了add、set以及previous等方法。
Iterator、Iteratable与ListIterator的更多相关文章
- 源码阅读—Iterator接口和LIstIterator接口
在继续看ArrayList源码之前,先了解Iterator接口和ListIterator接口,下篇文章详细讲解ArrayList是如何实现它们的. 我们知道,接口只是一种规范,当继承接口并实现其中的方 ...
- 详解 迭代器 —— Iterator接口、 ListIterator接口 与 并发修改异常
(请关注 本人"Collection集合"博文--<详解 Collection集合>) Iterator接口(迭代器): 概述: 对 collection 进行迭代的迭 ...
- Iterator之ListIterator简介
ListIterator是什么? (参考自百度百科) java中的ListIterator在Iterator基础上提供了add.set.previous等对列表的操作.但是ListIterator跟I ...
- Iterator和ListIterator区别
我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器).使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了. 但是在使用 ...
- Java容器类源码分析之Iterator与ListIterator迭代器(基于JDK8)
一.基本概念 迭代器是一个对象,也是一种设计模式,Java有两个用来实实现迭代器的接口,分别是Iterator接口和继承自Iterator的ListIterator接口.实现迭代器接口的类的对象有遍历 ...
- 09 Collection,Iterator,List,listIterator,Vector,ArrayList,LinkedList,泛型,增强for,可变参数,HashSet,LinkedHashSet,TreeSet
09 Collection,Iterator,List,listIterator,Vector,ArrayList,LinkedList,泛型,增强for,可变参数,HashSet,LinkedHas ...
- Java学习笔记之Iterator和ListIterator
原文:https://blog.csdn.net/GongchuangSu/article/details/51514380 Iterator接口是对collection进行迭代的迭代器,ListIt ...
- Iterator接口(迭代器)
目录 前言 原理 方法 异常 Iterator接口(迭代器) 前言 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对象, ...
- 设计模式 笔记 迭代器模式 Iterator
//---------------------------15/04/26---------------------------- //Iterator 迭代器模式----对象行为型模式 /* 1:意 ...
随机推荐
- codeforces 350 div2 D Magic Powder - 2 二分
D2. Magic Powder - 2 time limit per test 1 second memory limit per test 256 megabytes input standard ...
- html 画圆
<html> <head> <script type = "text/javascript" src = "https://d3js.org ...
- Flex布局兼容知识点总结
转载,原文http://www.cnblogs.com/tugenhua0707/p/5180841.html,部分截取 假设父容器class为 box,子项目为item.旧版语法如下:一:定义容器的 ...
- boosting方法
概述 Boosting基本思想: 通过改变训练数据的概率分布(训练数据的权值分布),学习多个弱分类器,并将它们线性组合,构成强分类器. Boosting算法要求基学习器能对特定的数据分布进行学习,这可 ...
- Confluence 6 选项 1 – 在 Confluence 中手动重建用户和用户组
当你只有少量的用户和用户组的时候,使用这个方法. 使用 Confluence 的系统管理员登录 Confluence. 进入用户目录管理界面,然后移动 内部目录(internal directory) ...
- UVA-10995 Educational Journey
The University of Calgary team qualified for the 28th ACM International Collegiate Programming Conte ...
- Oracle11g温习-第六章:控制文件
2013年4月27日 星期六 10:33 .控制文件的功能和特点 1) [定义数据库当前物理状态] 2) [维护数据的一致性] 如果控制文件中的检查点与数据文件中的一致,则说明数据一致,可以启动到 ...
- RAC配置(启停库)
关库顺序 :先关闭数据库 然后关闭节点资源 [root@rac1 ~]# srvctl stop database -d 数据库名[root@rac1 ~]# srvctl stop ins ...
- C#XML注释
注释 <c> 将说明中的文本标记为代码 <code> 提供了一种将多行指示为 ...
- jenkins安装笔记(一)
转载地址:https://www.cnblogs.com/sylvia-liu/p/4485311.html 自动化架构搭建过程中为实现当开发源码更新时自动化脚本同步触发自动执行,使用到持续集成工具J ...