Iterator和Iterable
Java遍历List有三种方式
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i) + ", ");
}
// for-each,实际也是Iterator
for (String s : list) {
System.out.println(s + ", ");
}
// 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next() + ", ");
}
}
Iterator源码
public interface Iterator<E> {
// 判断集合中是否存在下一个对象
boolean hasNext();
// 返回集合中的下一个对象,并将访问指针移动一位
E next();
// 删除集合中调用next()方法返回的对象
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}
- 它对 Iterable 的每个元素执行给定操作,具体指定的操作需要自己写Consumer接口通过accept方法回调出来。
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
- List 的关系图谱中并没有直接使用 Iterator,而是使用 Iterable 做了过渡
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);
}
}
ArrayList重写了Iterable的iterator方法
public Iterator<E> iterator() {
return new Itr();
}
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;
Itr() {}
// 判断是否还有下个元素
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
// 获取下个元素
public E next() {
checkForComodification();
// 记录当前迭代器的位置
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
// 获取 ArrayList 对象的内部数组
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
// 将游标位置加 1,为下一次迭代做准备
cursor = i + 1;
// 记录上一个元素的索引
return (E) elementData[lastRet = i];
}
// 删除最后一个返回的元素,迭代器只能删除最后一次调用 next 方法返回的元素
public void remove() {
// 如果上一次调用 next 方法之前没有调用 remove 方法,则抛出 IllegalStateException 异常
if (lastRet < 0)
throw new IllegalStateException();
// 检查在最后一次调用 next 方法之后是否进行了结构性修改
checkForComodification();
try {
// 调用 ArrayList 对象的 remove(int index) 方法删除上一个元素
ArrayList.this.remove(lastRet);
// 将游标位置设置为上一个元素的位置
cursor = lastRet;
// 将上一个元素的索引设置为 -1,表示没有上一个元素
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();
}
}
- Map 就没办法直接使用 for-each,因为 Map 没有实现 Iterable 接口,只有通过
map.entrySet()、map.keySet()、map.values()这种返回一个 Collection 的方式才能 使用 for-each。
LinkedList的父类 AbstractSequentialList重写 Iterable 接口的 iterator 方法
- LinkedList 并没有直接重写 Iterable 接口的 iterator 方法,而是由它的父类 AbstractSequentialList 来完成
public Iterator<E> iterator() {
return listIterator();
}
- LinkedList重写了listIterator方法
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
// 在遍历List 时可以从任意下标开始遍历,而且支持双向遍历。
// Iterator 不仅支持 List,还支持 Set,但 ListIterator 就只支持 List
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove();
void set(E e);
void add(E e);
}
- LinkedList的逆序遍历
private class DescendingIterator implements Iterator<E> {
// 使用 ListItr 对象进行逆向遍历。
private final ListItr itr = new ListItr(size());
// 判断是否还有下一个元素。
public boolean hasNext() {
return itr.hasPrevious();
}
// 获取下一个元素。
public E next() {
return itr.previous();
}
// 删除最后一个返回的元素。
public void remove() {
itr.remove();
}
}
Iterator和Iterable的更多相关文章
- Iterator和Iterable的区别以及使用
Iterator和Iterable的区别以及使用 1.什么是迭代器 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址.迭代 ...
- 【转】Java迭代:Iterator和Iterable接口
Java迭代 : Iterator和Iterable接口 从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... ...
- Iterator 和 Iterable 区别和联系
首先预览下Java源码中的Iterator和Iterable: Iterable接口: public interface Iterable<T> {//这里只摘录接口中的抽象方法 /** ...
- iterator与iterable的区别和联系
iterator与iterable 用Iterator模式实现遍历集合Iterator模式是用于遍历集合类的标准访问方法.它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内 ...
- python generator iterator和iterable object
1 iterable object list.dict.set.tuple.file(在每行上iterate)等都是iterable object,但是它们不是iterator.但是它们可以转换成it ...
- iterator和iterable的区别
相关博客: http://blog.csdn.net/lipengcn/article/details/51700153 Java中Iterable和Iterator的辨析 http ...
- Java迭代 : Iterator和Iterable接口
从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... Iterator: 在英语中or 结尾是都是表示 .. ...
- Iterator 和 Iterable 差别和联系
用Iterator模式实现遍历集合 Iterator模式是用于遍历集合类的标准訪问方法.它能够把訪问逻辑从不同类型的集合类中抽象出来,从而避免向client暴露集合的内部结构. 比如,假设没有使用I ...
- Iterator、Iterable接口的使用及详解
Java集合类库将集合的接口与实现分离.同样的接口,可以有不同的实现. Java集合类的基本接口是Collection接口.而Collection接口必须实现Iterator接口. 以下图表示集合框架 ...
- 【转】Python 中 Iterator和Iterable的区别
Python中 list,truple,str,dict这些都可以被迭代,但他们并不是迭代器.为什么? 因为和迭代器相比有一个很大的不同,list/truple/map/dict这些数据的大小是确定的 ...
随机推荐
- 【转载】 在Ubuntu环境下,搜狗输入法乱码问题的解决
原文作者:高坦的博客 | Tan's Blog 原文链接:https://www.cnblogs.com/gtscool/p/12234104.html本文采用 BY-NC-SA 许可协议.转载请注明 ...
- 【牛客刷题】HJ13 句子逆序
题目链接 题目本身不难,但是牛客的输入样例很坑,因此只好使用bufio来进行输入了: package main import ( "bufio" "fmt" & ...
- 3. EMC EMS EMI
1. 定义 1.1 EMC(Electromagnetic Compatibility) 电磁兼容性(EMC)是指系统正常工作的能力,不受其正常环境中电磁现象的干扰,不产生干扰其他设备的电干扰. 1. ...
- 对话框通过EndDialog返回值传值回父窗体
1. 调用对话(模式调用) MyDialog dlg(this); INT_PTR nRet=dlg.DoModal(); //这里接收模态对话框传出来的指针 if(nRet==IDCANCEL) / ...
- [Linux]yum下载慢!!
有全局代理,但是yum下载特别慢,怎么办? 确保/etc/yum.conf文件中代理配置的语法正确,包括代理服务器的地址和端口号,如下所示: proxy=http://your_proxy_serve ...
- Visual studio 2019 无法推送代码到 GitHub
博客转载:VS2022 无法推送到GitHub,也无法克隆项目_vs连不上github-CSDN博客 问题描述` 使用vs2019 git无法推送到github 解决办法` 按照大神的描述设置,非常好 ...
- 【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户
背景 OSN 是一种 fee on transfer 代币,会根据用户分红账户的余额对用户发放分红.攻击者利用漏洞增发分红账户的余额,随后触发分红机制完成获利. OSN:https://bscscan ...
- androi studio bitmap 压缩后 图片方向异常
Android 使用 Camera2拍照后,获得 byte[] data,随后使用 BitmapFactory.decodeByteArray 压缩 导致图片方向异常 /* * 避免出现方向异常 * ...
- MyBatis日志工厂
目录 日志工厂 标准日志实现 Log4j 使用步骤: 日志工厂 我们在测试SQL的时候,要是能够在控制台输出 SQL 的话,是不是就能够有更快的排错效率? 如果一个 数据库相关的操作出现了问题,我们可 ...
- spark 自定义 accumulator
默认的accumulator 只是最简单的 int/float 有时候我需要一个map来作为accumulator 这样,就可以处理 <string, int>类型的计数了. 此外我还需要 ...