内容简介:Java 中有关抽象的可遍历的对象有 Iterator, Iterable 和 Java 8 的 Stream, Iterable 可简单的用如下代码转换为 Stream再回过头来,为什么要把 Iterator 或 Iterable 转换为 Stream, 因为 Iterator 和 Iterable 只提供有限的遍历操作,如 Iterator 接口的全部四个方法同样 Iterable 也只有
Java 中有关抽象的可遍历的对象有 Iterator, Iterable 和 Java 8 的 Stream, Iterable 可简单的用如下代码转换为 Stream
StreamSupport.stream(iterable.spliterator(), false)
再回过头来,为什么要把 Iterator 或 Iterable 转换为 Stream, 因为 Iterator 和 Iterable 只提供有限的遍历操作,如 Iterator 接口的全部四个方法
hasNext() next() forEachRemaining(consumer) remove()
同样 Iterable 也只有 iterator()
, forEach(consumer)
, 和 spliterator()
方法。而 Java 8 的 Stream 就大不一样的,带有大量的链式操作方法,如 filter, map, flatMap, collect 等。
因此如果我们已有一个 Iterator 类型,能够被转换为 Stream 类型的话将会大大简化后续的转换,处理操作。具体的从 Iterator 到 Stream 的转换方式有两种
通过 Spliterators.spliteratorUnknownSize(...) 方法变 Iterator 为 Stream
由于 Iterator 的大小是不确定的,有多少个元素完全由 hasNext() 决定的, spliteratorUnknownSize()
方法正好应了这一情景。代码如下
Iterator<Integer> sourceIterator = Arrays.asList(3, 1, 2, null, 2).iterator(); Stream<Integer> targetStream = StreamSupport.stream( Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.SORTED), false); System.out.println(Arrays.toString(targetStream.toArray()));
输出会是
[3, 1, 2, null, 2]
前面的 Spliterator.SORTED 参数值是 characteristics
, 预定义了七个常量值,但是对于 Spliterators.splieratorUnknownSize(...)
方法来说无论传什么都不会影响到最终的结果。比如我们可以做下面一个测试
public void test(int characteristics) { System.out.printf("characteristics %5d: ", characteristics); Iterator<Integer> sourceIterator = Arrays.asList(3, 1, 2, null, 2).iterator(); Stream<Integer> targetStream = StreamSupport.stream( Spliterators.spliteratorUnknownSize(sourceIterator, characteristics), false); System.out.println(Arrays.toString(targetStream.toArray())); } Arrays.asList( Spliterator.CONCURRENT, Spliterator.DISTINCT, Spliterator.IMMUTABLE, Spliterator.NONNULL, Spliterator.SIZED, Spliterator.SORTED, Spliterator.SUBSIZED).forEach(this::test);
输出结果如下:
characteristics 4096: [3, 1, 2, null, 2] characteristics 1: [3, 1, 2, null, 2] characteristics 1024: [3, 1, 2, null, 2] characteristics 256: [3, 1, 2, null, 2] characteristics 64: [3, 1, 2, null, 2] characteristics 4: [3, 1, 2, null, 2] characteristics 16384: [3, 1, 2, null, 2]
这里的 characteristics 传什么都行。
根据下面的分析,characteristics 用不着从常量定义中挑选,直接给 0
就行,写成下面那样
Spliterators.spliteratorUnknownSize(sourceIterator, 0)
经由 Iterable 把 Iterator 转换为 Stream
像最前面那样 Iterable 可以轻松转换为 Stream, 所以先把 Iterator 变为 Iterable 再转化为 Stream。
Iterator<Integer> sourceIterator = Arrays.asList(3, 1, 2, null, 2).iterator(); Iterable<Integer> iterable = () -> sourceIterator; Stream<Integer> targetStream = StreamSupport.stream(iterable.spliterator(), false); System.out.println(Arrays.toString(targetStream.toArray()));
注意到上面由一个 Lambda 变 Iterator 为 Iterable 了,看 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); } }
只有一个抽象方法(其他两个为默认方法),所以可用
Iterable<Integer> iterable = () -> sourceIterator
声明一个 iterator() 返回 sourceIterator 的 Iterable 类型。
再看 Iterable 的默认方法 spliterator() 的实现,同样是调用的
Spliterators.spliteratorUnknownsSize(iterator(), 0)
这里的第二个参数 0
实际上不是 Spliterator 中的 CONCURRENT
, DISTINCT
, IMMUTABLE
, NONNULL
, SIZED
, SORTED
, SUBSIZED
中的任何一个值。
写到这里,通过参源代码阅读,前面所述的两种方式实质上没有一点区别。
对由 Iterator 转换为 Stream 的一个测试
下面例子创建一个无限大小的 Iterator (hasNext() 永远返回 true),然后由它转换成 Stream, 再调用 Stream 的 filter 和 limit 来检验它是一个真正的 Stream
public Stream<Integer> convert(Iterator<Integer> sourceIterator) { Iterable<Integer> iterable = () -> sourceIterator; return StreamSupport.stream(iterable.spliterator(), false); } @Test public void test() { Iterator<Integer> sourceIterator = new Iterator<Integer>() { private AtomicInteger count = new AtomicInteger(0); private Random random = new Random(); @Override public boolean hasNext() { return true; } @Override public Integer next() { System.out.println("next: " + count.incrementAndGet()); //每一次遍历将会打印计数 return random.nextInt(99999); } }; //无条件的获得 3 个元素即可 System.out.println(Arrays.toString(convert(sourceIterator).limit(3).toArray())); System.out.println(); //从流中过虑出小于 30000 的 3 个元素 System.out.println(Arrays.toString(convert(sourceIterator).filter(a -> a < 30000).limit(3).toArray())); }
下面是某一次的执行输出
next: 1 next: 2 next: 3 [11430, 20177, 64297] next: 4 next: 5 next: 6 next: 7 next: 8 next: 9 next: 10 next: 11 next: 12 next: 13 next: 14 next: 15 next: 16 next: 17 [19378, 16142, 9354]
该行为与 Stream 是相吻合的,因为 Stream 是一个 Lazy 的,它确实是一个流,无需事选知道流中将会有多少元素。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- JavaScript进阶系列-类型转换、隐式类型转换
- Android 多国语言转换 Excel 和 Excel 转换为 string
- [SSL证书转换(一)]关于JKS 转换成 CRT 和 KEY
- c++中几种常见的类型转换。int与string的转换,float与string的转换以及string和long类型之间的相互...
- Protocol Buffer使用转换工具将proto文件转换成Java文件流程及使用
- 开源 | Alita:一套把 React Native 代码转换成微信小程序代码的转换引擎工具
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Google Maps API 3
Gabriel Svennerberg / Apress / 2010-07-27 / $39.99
This book is about the next generation of the Google Maps API. It will provide the reader with the skills and knowledge necessary to incorporate Google Maps v3 on web pages in both desktop and mobile ......一起来看看 《Beginning Google Maps API 3》 这本书的介绍吧!
Base64 编码/解码
Base64 编码/解码
XML、JSON 在线转换
在线XML、JSON转换工具