Iterable源码分析

Iterable 源码分析

Iterable简介

  Iterable是从jdk1.5就存在的接口,其实我们经常用到它的功能,就是for-each,要想使用for-each,就必须实现此接口。

API简介

// since 1.5
Iterator<T> iterator();
// since 1.8
default void forEach(Consumer<? super T> action){}
// since 1.8
default Spliterator<T> spliterator(){}

源码分析

public interface Iterable<T> {
   	// 返回T元素类型的迭代器
    Iterator<T> iterator();

  	// 对Iterable的每个元素执行给定操作,直到处理完所有元素或操作引发异常。
    // 除非实现类另有指定,否则操作按迭代顺序执行(如果指定了迭代顺序)
    // Consumer 四大函数接口,不在本章叙述范围内 后续会有文章专门讲解java8函数编程
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    
    // 可分割的迭代器,是1.8退出的用于并行遍历元素而设计的一个迭代器
    	 // 官方文档说明默认的实现分割的能力比较差,推荐覆盖默认实现。
    	 // 可以跟上面的Iterator功能区分;一个是顺序遍历,一个是并行遍历
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

foreach遍历、for循环和Iterable的渊源

  • for 循环遍历集合 以及反编译后的代码
ArrayList<Integer> a1 = new ArrayList<Integer>(16);
/*0-5*/
for (int i = 0; i < 6; i++) {
a1.add(i);
}
for (int i = 0; i < 6; i++) {
System.out.println(i);
}
/*************反编译后的代码**********************/
ArrayList<Integer> a1 = new ArrayList(16);
int i;
for(i = 0; i < 6; ++i) {
a1.add(i);
}
for(i = 0; i < 6; ++i) {
System.out.println(i);
}
  • foreach遍历集合以及反编译后的代码
ArrayList<Integer> a1 = new ArrayList<Integer>(16);
/*0-5*/
for (int i = 0; i < 6; i++) {
a1.add(i);
}
// foreach循环
for(Integer i : a1){
System.out.println(i);
}
/***************反编译后的代码*******************/
ArrayList<Integer> a1 = new ArrayList(16);

for(int i = 0; i < 6; ++i) {
a1.add(i);
}
// 反编译之后发现是调用了集合的Iterator来实现的
Iterator var4 = a1.iterator();

while(var4.hasNext()) {
Integer i = (Integer)var4.next();
System.out.println(i);
}
  • foreach遍历数组以及反编译后的代码
String[] str = {"a", "b", "c", "d"};
for (String s :
str) {
System.out.println(s);
}
/***************反编译后的代码**********************/
String[] str = new String[]{"a", "b", "c", "d"};
String[] var2 = str;
int var3 = str.length;

for(int var4 = 0; var4 < var3; ++var4) {
String s = var2[var4];
System.out.println(s);
}

从上面几个例子可以知道:
1:foreach循环底层调用的是iterator这个说法是错的,应该针对性的讲。对于数组,>foreach底层的实现是简单的for循环,而对于集合,底层的实现则是通过Iterator来实现的
2:只有实现了Itearable接口的类才能使用foreach遍历也是错的。对于数组,foreach的底层实现则是for,它并没有实现iterator接口


迭代器原理

java 集合类库的迭代器跟其他类库的迭代器在概念上有着重要的区别。比如:C++的标准模板库的迭代器是根据数组索引建模的。如果给定这样一个迭代器,就可以查看指定位置上的元素,就像是知道数组索引i,就可以查看数组元素a[i]一样,不需要查找元素,就可以将迭代器向前移动一个位置。但是Java迭代器并不是如此。java迭代器查找操作和位置变更是紧密相连的,查找元素的唯一方式就是调用next,而在执行查找的同时,迭代器位置随之向前移动,因此,应该将java迭代器 认为是位于两个元素之间。当调用next时候,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用

1544952542193

很明显从图中可知,当调用it.next的时候,会查找是否有元素,然后迭代器的指向从A到B位置。

实战演练

  • Iterator 遍历元素
String[] s = {"a", "b", "c", "d", "e"};
List<String> list = Arrays.asList(s);
Iterator<String> itr = list.iterator();
while (itr.hasNext()){
System.out.println(itr.next());
}
  • 循环输出字符串数组中的内容
String[] s = {"a", "b", "c", "d", "e"};
List<String> list1 = Arrays.asList(s);
// lambda表达式
list1.forEach(cc -> System.out.println(cc));
  • 并行遍历元素
String[] str = {"a", "b", "c", "d", "e"};
List<String> list = Arrays.asList(str);
Spliterator<String> s = list.spliterator();
Spliterator<String> s1 =  s.trySplit();
// 返回值是a,b  split 分割成两个集合
// 一个为 a,b  一个为 c,d,e
s.forEachRemaining(System.out :: println);
s1.forEachRemaining(System.out :: println);

总结

  1. 并不是实现了Iterable接口的类才能使用foreach遍历,数组就没有实现Iterable接口,数组使用foreach,反编译后的代码其实是通过for循环来完成这个遍历的功能。
  2. 1.8新增了两个默认实现:一个是foreach,一个是Spliterator
  3. foreachSpliterator一个是顺序遍历元素,一个是并行遍历元素

如果有小伙伴觉得我写的不错的话可以关注一下我的博客,我会一直持续更新,也可以支持一下我的公众号哦:java架构师小密圈,会分享架构师所必须深入研究的技术,比如netty,分布式,性能优化,spring源码分析,mybatis源码分析,等等等,同时还会分享一些赚钱理财的小套路哦,欢迎大家来支持,一起学习成长,程序员不仅仅是搬瓦工!
公众号:分享系列好文章
java架构师小密圈

交流群:群友互相分享资料
java架构师小密圈

ObservableZipIterable 是 RxJava 中的一个类,用于将多个 Observable 转换成单个 Observable ,并将它们的元素打包成一个元素。下面是该类的源码分析: ``` final class ObservableZipIterable<T, U, V> extends Observable<V> { final Iterable<? extends ObservableSource<? extends T>> sources; final Function<? super Object[], ? extends V> zipper; ObservableZipIterable(Iterable<? extends ObservableSource<? extends T>> sources, Function<? super Object[], ? extends V> zipper) { this.sources = sources; this.zipper = zipper; } @Override public void subscribeActual(Observer<? super V> s) { @SuppressWarnings("unchecked") Iterator<? extends ObservableSource<? extends T>> it = sources.iterator(); // 检查源 Observable 是否为空 if (!it.hasNext()) { EmptyDisposable.error(new NoSuchElementException(), s); return; } // 创建一个动态数组,用于缓存每个源 Observable 的元素 // 这里使用了可变长数组 ArrayList,因为不知道每个源 Observable 会产生多少个元素 // 使用 ArrayList 可以动态地添加元素 int n = 0; ObservableSource<? extends T>[] sources = new ObservableSource[8]; try { while (it.hasNext()) { ObservableSource<? extends T> p = it.next(); if (p == null) { EmptyDisposable.error(new NullPointerException("One of the sources is null"), s); return; } if (n == sources.length) { ObservableSource<? extends T>[] b = new ObservableSource[n + (n >> 2)]; System.arraycopy(sources, 0, b, 0, n); sources = b; } sources[n++] = p; } } catch (Throwable e) { Exceptions.throwIfFatal(e); EmptyDisposable.error(e, s); return; } // 创建一个数组,用于缓存每个源 Observable 的 Observer // 与上面的 sources 数组一样,这里也使用了 ArrayList,因为不知道每个源 Observable 会产生多少个元素 // 使用 ArrayList 可以动态地添加元素 ObservableZip<T>[] zip = new ObservableZip[n]; for (int i = 0; i < n; i++) { zip[i] = new ObservableZip<T>(sources[i]); } // 创建一个 ZipCoordinator 对象,用于协调多个 Observable 的订阅元素的打包 ZipCoordinator<T, V> coordinator = new ZipCoordinator<T, V>(s, zipper, n, zip); // 订阅每个源 Observable coordinator.subscribe(zip); // 执行协调器的 run 方法,开始打包元素 coordinator.run(); } } ``` 从上面的源码中可以看出,ObservableZipIterable 类实际上是一个 Observable 的子类,它的 subscribeActual 方法用于订阅源 Observable,并将它们的元素打包成一个元素。 在 subscribeActual 方法中,首先使用 sources.iterator() 获取源 Observable 的迭代器,然后依次遍历每个源 Observable,并把它们的元素缓存在一个动态数组中。如果在遍历过程中遇到了 null 值或者源 Observable 为空,则会发送 onError 事件,并终止订阅。 接着,根据每个源 Observable 的个数创建一个 ObservableZip 数组,用于缓存每个源 Observable 的 Observer。然后创建一个 ZipCoordinator 对象,用于协调多个 Observable 的订阅元素的打包。 最后,订阅每个源 Observable,并执行协调器的 run 方法,开始打包元素。在 run 方法中,协调器会等待每个源 Observable 发送元素,并将它们打包成一个元素,然后发送给订阅者。如果有任意一个源 Observable 发出了 onError 事件,则会直接发送 onError 事件,并终止订阅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mindcarver

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值