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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 23:22:14  来源:igfitidea点击:

Why does Stream<T> not implement Iterable<T>?

javajava-8java-streamiterable

提问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 Iterableimplies reusability, whereas Streamis something that can only be used once — more like an Iterator.

If Streamextended Iterablethen existing code might be surprised when it receives an Iterablethat throws an Exceptionthe second time they do for (element : iterable).

我认为主要原因是这Iterable意味着可重用性,而Stream是只能使用一次的东西——更像是一个Iterator.

如果Stream扩展,Iterable那么现有代码可能会在收到第二次Iterable抛出 an时感到惊讶。Exceptionfor (element : iterable)

回答by ZhongYu

To convert a Streamto an Iterable, you can do

要将 a 转换Stream为 an Iterable,您可以执行

Stream<X> stream = null;
Iterable<X> iterable = stream::iterator

To pass a Streamto 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

I would like to point out that StreamExdoes implement Iterable(and Stream), as well as a host of other immensely awesome functionality missing from Stream.

我想指出,它StreamEx确实实现了Iterable(和Stream),以及Stream.

回答by Zenexer

kennytm describedwhy it's unsafe to treat a Streamas an Iterable, and Zhong Yu offered a workaroundthat permits using a Streamas in Iterable, albeit in an unsafe manner. It's possible to get the best of both worlds: a reusable Iterablefrom a Streamthat meets all the guarantees made by the Iterablespecification.

kennytm 描述了为什么将 aStream视为 an是不安全的Iterable,并且钟宇提供了一种允许使用Streamas in的变通方法Iterable,尽管以不安全的方式。这是有可能得到两全其美:可再用IterableStream满足全部由作出的保证Iterable规范。

Note: SomeTypeis 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::iteratorwould 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 Iterableand Streamare about. They are supposed to be lazy.

并不完美,因为它会获取从流的所有项目,并把它们成List,这不正是IterableStream约。他们应该是懒惰的

回答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 forloop 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

Streamdoes not implement Iterable. The general understanding of Iterableis anything that can be iterated upon, often again and again. Streammay 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 Supplierbelow 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);
    }