Java 为什么 Stream<T> 没有实现 Iterable<T>?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20129762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does Stream<T> not implement Iterable<T>?
提问by roim
In Java 8 we have the class Stream<T>, which curiously have a method
在 Java 8 中,我们有类Stream<T>,奇怪的是它有一个方法
Iterator<T> iterator()
So you would expect it to implement interface Iterable<T>, which requires exactly this method, but that's not the case.
所以你会期望它实现接口Iterable<T>,它需要这个方法,但事实并非如此。
When I want to iterate over a Stream using a foreach loop, I have to do something like
当我想使用 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)) { ... }
Am I missing something here?
我在这里错过了什么吗?
采纳答案by kennytm
People have already asked the same on the mailing list?. The main reason is Iterable also has a re-iterable semantic, while Stream is not.
人们已经在邮件列表上问过同样的问题?。主要原因是 Iterable 也有可重复的语义,而 Stream 没有。
I think the main reason is that
Iterable
implies reusability, whereasStream
is something that can only be used once — more like anIterator
.If
Stream
extendedIterable
then existing code might be surprised when it receives anIterable
that throws anException
the second time they dofor (element : iterable)
.
我认为主要原因是这
Iterable
意味着可重用性,而Stream
是只能使用一次的东西——更像是一个Iterator
.如果
Stream
扩展,Iterable
那么现有代码可能会在收到第二次Iterable
抛出 an时感到惊讶。Exception
for (element : iterable)
回答by ZhongYu
To convert a Stream
to an Iterable
, you can do
要将 a 转换Stream
为 an Iterable
,您可以执行
Stream<X> stream = null;
Iterable<X> iterable = stream::iterator
To pass a Stream
to a method that expects Iterable
,
要将 a 传递Stream
给期望 的方法Iterable
,
void foo(Iterable<X> iterable)
simply
简单地
foo(stream::iterator)
however it probably looks funny; it might be better to be a little bit more explicit
但它可能看起来很有趣;更明确一点可能会更好
foo( (Iterable<X>)stream::iterator );
回答by Aleksandr Dubinsky
回答by Zenexer
kennytm describedwhy it's unsafe to treat a Stream
as an Iterable
, and Zhong Yu offered a workaroundthat permits using a Stream
as in Iterable
, albeit in an unsafe manner. It's possible to get the best of both worlds: a reusable Iterable
from a Stream
that meets all the guarantees made by the Iterable
specification.
kennytm 描述了为什么将 aStream
视为 an是不安全的Iterable
,并且钟宇提供了一种允许使用Stream
as in的变通方法Iterable
,尽管以不安全的方式。这是有可能得到两全其美:可再用Iterable
从Stream
满足全部由作出的保证Iterable
规范。
Note: SomeType
is not a type parameter here--you need to replace it with a proper type (e.g., String
) or resort to reflection
注意:SomeType
这里不是类型参数——你需要用适当的类型(例如,String
)替换它或诉诸反射
Stream<SomeType> stream = ...;
Iterable<SomeType> iterable = stream.collect(toList()):
There is one major disadvantage:
有一个主要缺点:
The benefits of lazy iteration will be lost. If you planned to immediately iterate over all values in the current thread, any overhead will be negligible. However, if you planned to iterate only partially or in a different thread, this immediate and complete iteration could have unintended consequences.
惰性迭代的好处将丢失。如果您计划立即迭代当前线程中的所有值,则任何开销都可以忽略不计。但是,如果您计划仅部分迭代或在不同的线程中进行迭代,则这种立即且完整的迭代可能会产生意想不到的后果。
The big advantage, of course, is that you can reuse the Iterable
, whereas (Iterable<SomeType>) stream::iterator
would only permit a single use. If the receiving code will be iterating over the collection multiple times, this is not only necessary, but likely beneficial to performance.
当然,最大的优点是您可以重复使用Iterable
,而(Iterable<SomeType>) stream::iterator
只允许使用一次。如果接收代码将多次迭代集合,这不仅是必要的,而且可能对性能有益。
回答by yegor256
Not perfect, but will work:
不完美,但会起作用:
iterable = stream.collect(Collectors.toList());
Not perfect because it will fetch all items from the stream and put them into that List
, which is not exactly what Iterable
and Stream
are about. They are supposed to be lazy.
并不完美,因为它会获取从流的所有项目,并把它们成List
,这不正是Iterable
与Stream
约。他们应该是懒惰的。
回答by John McClean
If you don't mind using third party libraries cyclops-reactdefines a Stream that implements both Stream and Iterable and is replayable too (solving the problem kennytm described).
如果您不介意使用第三方库,cyclops-react定义了一个 Stream ,它实现了 Stream 和 Iterable 并且也可以重播(解决了kennytm 描述的问题)。
Stream<String> stream = ReactiveSeq.of("hello","world")
.map(s->"prefix-"+s);
or :-
或者 :-
Iterable<String> stream = ReactiveSeq.of("hello","world")
.map(s->"prefix-"+s);
stream.forEach(System.out::println);
stream.forEach(System.out::println);
[Disclosure I am the lead developer of cyclops-react]
[披露我是独眼巨人反应的首席开发人员]
回答by Rich
You can use a Stream in a for
loop as follows:
您可以for
按如下方式在循环中使用 Stream :
Stream<T> stream = ...;
for (T x : (Iterable<T>) stream::iterator) {
...
}
(Run this snippet here)
(This uses a Java 8 functional interface cast.)
(这使用 Java 8 函数式接口转换。)
(This is covered in some of the comments above (e.g. Aleksandr Dubinsky), but I wanted to pull it out into an answer to make it more visible.)
(这在上面的一些评论中有所涉及(例如Aleksandr Dubinsky),但我想将其提取为答案以使其更加明显。)
回答by BullyWiiPlaza
You can iterate over all files in a folder using Stream<Path>
like this:
您可以使用Stream<Path>
如下方式遍历文件夹中的所有文件:
Path path = Paths.get("...");
Stream<Path> files = Files.list(path);
for (Iterator<Path> it = files.iterator(); it.hasNext(); )
{
Object file = it.next();
// ...
}
回答by Ashish Tyagi
Stream
does not implement Iterable
. The general understanding of Iterable
is anything that can be iterated upon, often again and again. Stream
may not be replayable.
Stream
不执行Iterable
。一般的理解Iterable
是任何可以反复迭代的东西。Stream
可能无法重播。
The only workaround that I can think of, where an iterable based on a stream is replayable too, is to re-create the stream. I am using a Supplier
below to create a new instance of stream, everytime a new iterator is created.
我能想到的唯一解决方法是重新创建流,其中基于流的可迭代对象也可重播。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);
}