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的更多相关文章

  1. Iterator和Iterable的区别以及使用

    Iterator和Iterable的区别以及使用   1.什么是迭代器 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址.迭代 ...

  2. 【转】Java迭代:Iterator和Iterable接口

    Java迭代 : Iterator和Iterable接口 从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... ...

  3. Iterator 和 Iterable 区别和联系

    首先预览下Java源码中的Iterator和Iterable: Iterable接口: public interface Iterable<T> {//这里只摘录接口中的抽象方法 /** ...

  4. iterator与iterable的区别和联系

    iterator与iterable   用Iterator模式实现遍历集合Iterator模式是用于遍历集合类的标准访问方法.它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内 ...

  5. python generator iterator和iterable object

    1 iterable object list.dict.set.tuple.file(在每行上iterate)等都是iterable object,但是它们不是iterator.但是它们可以转换成it ...

  6. iterator和iterable的区别

    相关博客:  http://blog.csdn.net/lipengcn/article/details/51700153         Java中Iterable和Iterator的辨析 http ...

  7. Java迭代 : Iterator和Iterable接口

    从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... Iterator:   在英语中or 结尾是都是表示 .. ...

  8. Iterator 和 Iterable 差别和联系

    用Iterator模式实现遍历集合  Iterator模式是用于遍历集合类的标准訪问方法.它能够把訪问逻辑从不同类型的集合类中抽象出来,从而避免向client暴露集合的内部结构. 比如,假设没有使用I ...

  9. Iterator、Iterable接口的使用及详解

    Java集合类库将集合的接口与实现分离.同样的接口,可以有不同的实现. Java集合类的基本接口是Collection接口.而Collection接口必须实现Iterator接口. 以下图表示集合框架 ...

  10. 【转】Python 中 Iterator和Iterable的区别

    Python中 list,truple,str,dict这些都可以被迭代,但他们并不是迭代器.为什么? 因为和迭代器相比有一个很大的不同,list/truple/map/dict这些数据的大小是确定的 ...

随机推荐

  1. 乌克兰学者的学术图谱case3

    ============================================ 背景: 弗兰采维奇材料问题研究是欧洲最大的材料科研院所,在核电.航空.航天.军工及其他装备制造领域的先进材料研 ...

  2. 【转载】网络协议之:sctp流控制传输协议

    原文地址: https://www.cnblogs.com/flydean/p/16277006.html ============================================== ...

  3. Opentelemetry collector用法

    Opentelemetry collector用法 目录 Opentelemetry collector用法 Service Extensions healthcheckextension Pipel ...

  4. quartz执行卡死--强制中断线程

    在quartz中经常会碰到由于网络问题或者一些其他不稳定因素导致的线程卡死问题,这往往会导致数据处理的延时.而有时候一时无法定位到卡死的原因,为了降低系统风险,我们就会希望有一个超时机制,当执行超时时 ...

  5. 瑞芯微|如何让拥有双网口的Linux设备实现数据包转发?【超实用】

    本文主要讲解如何,解决基于3568实现双网口互通问题. 一.组网 如下图所示: rk3568自带2个千兆以太口,对应网卡名称为:eth0.eth1 pc1和pc2分别连接这2个网口 pc1与eth0连 ...

  6. WCF实例管理

    实例管理是对WCF使用的一系列技术的总称,通过它可以将客户端的请求绑定到服务实例上,并根据客户端请求的类型以确定服务实例的管理方式.由于应用程序在可扩展,性能,吞吐量,事物与对垒调用等方面存在巨大的差 ...

  7. java_类方法&对象方法

    int new; 类方法 不能写入和访问其中的对象属性 可以直接通过类调用 通过类调用类方法,没有具体的对象, 所以 不可以访问对象属性, 但是可以访问类属性 public static void d ...

  8. 【VMware VCF】VCF 5.2:挂载远程 vSAN 数据存储。

    VMware vSAN 解决方案中,为了充分利用 vSAN HCI 集群内的存储资源, vSAN HCI 和 vSAN HCI 集群之间可以相互共享存储资源,这种解决方案早期叫 vSAN HCI Me ...

  9. Mysql table 调整table的字符集和校对规则

    ALTER TABLE `xxxx`.`xxx` CHARACTER SET = utf8mb4 , COLLATE = utf8mb4_0900_ai_ci ;

  10. SPSS25.0中文破解版安装教程及使用教程

    目录 第一步,下载链接: 下载并解压,管理员身份运行SPSS 25 64bit.exe: 第二步,安装过程一路默认,安装路径可以改变,然后等待安装完成即可: 第三步,安装完成后,立即启动SPPS; 第 ...