为什么Stream <T>不能实现Iterable <T>?
在Java 8中,我们有Stream <T>类,它好奇地有一个方法
Iterator<T> iterator()
所以你会希望它实现接口Iterable <T> ,它需要这个方法,但事实并非如此。
当我想使用foreach循环遍历Stream时,我必须做类似的事情
public static Iterable<T> getIterable(Stream<T> s) { return new Iterable<T> { @Override public Iterator<T> iterator() { return s.iterator(); } }; } for (T element : getIterable(s)) { ... }
我在这里错过了什么?
在邮件列表中已经有人问过这个问题了 。 主要原因是Iterable也有一个可重复的语义,而Stream不是。
我认为主要原因是可
Iterator
意味着可重用性,而Stream
只能被使用一次 – 更像Iterator
。如果
Stream
扩展Iterable
那么当它接收到一个Iterable
时,现有的代码可能会感到惊讶,这个Iterable
会在第二次抛出Exception
for (element : iterable)
时抛出Exception
。
要将Stream
转换为Iterable
,可以这样做
Stream<X> stream = null; Iterable<X> iterable = stream::iterator
要将Stream
传递给期望Iterable
,
void foo(Iterable<X> iterable)
只是
foo(stream::iterator)
然而,它可能看起来有趣。 稍微更清楚一点可能会更好一些
foo( (Iterable<X>)stream::iterator );
我想指出, StreamEx
确实实现了Iterable
(和Stream
)以及Stream
缺less的其他非常棒的function。
kennytm描述了为什么将Stream
作为Iterable
处理是不安全的, Zhongyu 提供了一种解决方法 ,允许在Iterable
使用Stream
,尽pipe这是一种不安全的方式。 可以得到两全其美的结果:一个Stream
中的可重用Iterable
,满足Iterable
规范所做的所有保证。
注意: SomeType
在这里不是一个types参数 – 你需要用适当的types(例如String
)replace它,或者使用reflection
Stream<SomeType> stream = ...; Iterable<SomeType> iterable = stream.collect(toList()):
有一个主要的缺点:
懒惰的迭代的好处将会丢失。 如果您计划立即迭代当前线程中的所有值,则任何开销都可以忽略不计。 但是,如果您计划仅部分迭代或在不同的线程中进行迭代,则可能会产生意想不到的后果。
当然,最大的好处就是可以重用Iterable
,而(Iterable<SomeType>) stream::iterator
只允许一次使用。 如果接收代码将迭代多次收集,这不仅是必要的,而且可能有利于性能。
您可以在for
循环中使用Stream,如下所示:
Stream<T> stream = ...; for (T x : (Iterable<T>) stream::iterator) { ... }
( 在这里运行这个片段 )
(这使用Java 8function接口强制转换。)
(这在上面的一些评论(例如Aleksandr Dubinsky )中已有介绍,但是我想把它提出来,使其更加明显)。
如果你不介意使用第三方库, cyclops-react定义了一个既实现Stream又Iterable并且可重放的Stream(解决kennytm描述的问题)。
Stream<String> stream = ReactiveSeq.of("hello","world") .map(s->"prefix-"+s);
要么 :-
Iterable<String> stream = ReactiveSeq.of("hello","world") .map(s->"prefix-"+s); stream.forEach(System.out::println); stream.forEach(System.out::println);
[披露我是独眼巨人反应的主要开发者]
不完美,但会工作:
iterable = stream.collect(Collectors.toList());
不完美,因为它会从stream中获取所有项目,并将它们放入该List
,这不完全是Iterable
和Stream
所关心的。 他们应该是懒惰的 。