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:意 ...
随机推荐
- HDU 2586 How far away ?(LCA在线算法实现)
http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:给出一棵树,求出树上任意两点之间的距离. 思路: 这道题可以利用LCA来做,记录好每个点距离根结点的 ...
- LA 4329 乒乓比赛
https://vjudge.net/problem/UVALive-4329 题意: 一条大街上住着n个兵乓球爱好者,经常组织比赛切磋技术.每个人都有一个不同的技能值ai.每场比赛需要3个人:两名选 ...
- html 画出矩形,鼠标弹起,矩形消失
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- Spring Boot 2.1.1.RELEASE 多数据源配置与使用
有时候,一个系统的功能,需要两个或两个以上的数据库, 在Spring Boot 中要如何配置? How to? #primary primary.spring.datasource.jdbc-url= ...
- Python day10 global关键字、函数递归、匿名函数、map函数的用法详解
1.global关键字 引用全局变量,在局部全局变量改变,也会改变,global相当于指针,将地址指向全局变量的name name='littlepage' def littepage(): glob ...
- Qt数据库_资料
1. QT笔记_数据库总结(一)-rojian-ChinaUnix博客.html http://blog.chinaunix.net/uid-28194872-id-3631462.html (里面有 ...
- Java8 Lambda代码备份
简单研究了一下,贴出来,相当于笔记 import java.lang.reflect.*; import java.util.ArrayList; import java.util.List; imp ...
- jsp动作之 forward
forward说明了,就想当于php的include,require函数.(但是它是跳转.forward之前的数据都不会显示) 这么说你明白了吗.就是包含,说的好听点就是跳转,但是url地址栏却是没有 ...
- English trip V1 - 7.My dream car 我梦想的车 Teacher:Lamb Key: famous for
中华In this lesson you will learn to describe an object(目标). 课上内容(Lesson) famous for 以…著称,闻名 国家(名词) ...
- 关于floyd 打印路径的问题
我们令 f[i][j] 表示从 i-->j的最短路上j前面的那个点. 显然初始化时 f[i][j]=i; (这样的话先判断一下i是否能到达j好点) 更新条件时,当发现通过点k能使最短 ...