在Java 8中,我们有类Stream<T>,它奇怪地有一个方法

Iterator<T> iterator()

所以你会期望它实现接口Iterable<T>,这需要这个方法,但事实并非如此。

当我想使用foreach循环遍历一个流时,我必须做如下的事情

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

我是不是遗漏了什么?


当前回答

你可以在for循环中使用一个流,如下所示:

Stream<T> stream = ...;

for (T x : (Iterable<T>) stream::iterator) {
    ...
}

(在这里运行这个片段)

(这使用了Java 8函数接口强制转换。)

(这在上面的一些评论中有涉及(例如Aleksandr Dubinsky),但我想把它拉出来,让它更明显。)

其他回答

你可以使用Stream<Path>遍历文件夹中的所有文件,如下所示:

Path path = Paths.get("...");
Stream<Path> files = Files.list(path);

for (Iterator<Path> it = files.iterator(); it.hasNext(); )
{
    Object file = it.next();

    // ...
}

你可以在for循环中使用一个流,如下所示:

Stream<T> stream = ...;

for (T x : (Iterable<T>) stream::iterator) {
    ...
}

(在这里运行这个片段)

(这使用了Java 8函数接口强制转换。)

(这在上面的一些评论中有涉及(例如Aleksandr Dubinsky),但我想把它拉出来,让它更明显。)

如果你不介意使用第三方库,cyclops-react定义了一个Stream,它实现了Stream和Iterable,并且也是可重玩的(解决了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);

[披露我是cyclops-react的主要开发者]

不完美,但可以:

iterable = stream.collect(Collectors.toList());

并不完美,因为它将从流中获取所有项并将其放入List中,这并不是Iterable和stream的确切含义。他们应该是懒惰的。

Stream没有实现Iterable。对Iterable的一般理解是任何可以反复迭代的东西。流可能不能重玩。

我能想到的唯一解决办法是,基于流的可迭代对象也是可重玩的,就是重新创建流。我在下面使用一个Supplier来创建一个新的stream实例,每次创建一个新的迭代器。

    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);
    }