在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)) { ... }
我在这里错过了什么吗?
答案 0 :(得分:181)
已经有人问同一个on the mailing list☺。主要原因是Iterable也有一个可重复的语义,而Stream则没有。
我认为主要原因是
Iterable
意味着可重用性,而Stream
只能使用一次 - 更像是Iterator
。如果
Stream
延长Iterable
,那么当现有代码收到Iterable
时会抛出Exception
第二次他们for (element : iterable)
。
答案 1 :(得分:143)
要将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 );
答案 2 :(得分:10)
我想指出StreamEx
确实实现了Iterable
(和Stream
),以及Stream
中缺少的其他一些非常棒的功能。< / p>
答案 3 :(得分:6)
kennytm described为什么将Stream
视为Iterable
并Zhong Yu offered a workaround允许Stream
使用Iterable
为Iterable
不安全1}},虽然是不安全的。可以充分利用这两个方面:来自Stream
的可重用Iterable
,它符合SomeType
规范所做的所有保证。
注意:String
此处不是类型参数 - 您需要将其替换为正确的类型(例如Stream<SomeType> stream = ...;
Iterable<SomeType> iterable = stream.collect(toList()):
)或诉诸于反射
Iterable
有一个主要缺点:
延迟迭代的好处将会丢失。如果您计划立即迭代当前线程中的所有值,则任何开销都可以忽略不计。但是,如果您计划仅部分迭代或在不同的线程中进行迭代,则此即时且完整的迭代可能会产生意想不到的后果。
当然,最大的好处是您可以重复使用(Iterable<SomeType>) stream::iterator
,而result_list
只允许一次使用。如果接收代码将多次遍历集合,这不仅是必要的,而且可能有利于性能。
答案 4 :(得分:3)
您可以在for
循环中使用Stream,如下所示:
Stream<T> stream = ...;
for (T x : (Iterable<T>) stream::iterator) {
...
}
(这使用Java 8功能界面演员。)
(上面的一些评论(例如Aleksandr Dubinsky)对此进行了介绍,但我想将其解决,以使其更加明显。)
答案 5 :(得分:2)
如果您不介意使用第三方库cyclops-react定义一个实现Stream和Iterable的Stream,并且也可以重放(解决问题kennytm described)。
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);
[披露我是独眼巨人反应的主要开发者]
答案 6 :(得分:2)
Stream
未实施Iterable
。对Iterable
的一般理解是可以反复进行的任何事情,通常是一次又一次。 Stream
可能无法重播。
我能想到的唯一解决方法是重新创建流,其中基于流的可迭代也是可重放的。每次创建新的迭代器时,我都使用下面的Supplier
创建一个新的流实例。
Supplier<Stream<Integer>> streamSupplier = () -> Stream.of(10);
Iterable<Integer> iterable = () -> streamSupplier.get().iterator();
for(int i : iterable) {
System.out.println(i);
}
// Can iterate again
for(int i : iterable) {
System.out.println(i);
}
答案 7 :(得分:0)
不完美,但会奏效:
iterable = stream.collect(Collectors.toList());
不完美,因为它会从流中获取所有项目并将其放入List
,这与Iterable
和Stream
不完全相同。它们应该是lazy。
答案 8 :(得分:0)
您可以使用Stream<Path>
迭代文件夹中的所有文件,如下所示:
Path path = Paths.get("...");
Stream<Path> files = Files.list(path);
for (Iterator<Path> it = files.iterator(); it.hasNext(); )
{
Object file = it.next();
// ...
}