为什么Stream <t>没有实现Iterable <t>?</t> </t>

时间:2013-11-21 19:06:22

标签: java java-8 java-stream iterable

在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)) { ... }

我在这里错过了什么吗?

9 个答案:

答案 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视为IterableZhong Yu offered a workaround允许Stream使用IterableIterable不安全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) {
    ...
}

(运行this snippet here

(这使用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,这与IterableStream不完全相同。它们应该是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();

    // ...
}