27

Stream继承一个iterator()方法来生成一个Iterator.

但我需要一个Iterable而不是一个Iterator.

例如,给定这个字符串:

String input = "this\n" +
        "that\n" +
        "the_other";

…我需要将字符串的这些部分作为Iterable一个特定的库传递。调用input.lines()产生一个Stream. 所以如果我能把它Stream变成Iterable它的一个元素,我就会被设置。

4

2 回答 2

33

正如为什么 Stream<T> 不实现 Iterable<T>?,anIterable承担着能够提供Iterator不止一次的 a 的期望,这是 aStream无法实现的。因此,虽然您可以创建一个Iterableout of aStream以供临时使用,但您必须小心是否可能存在多次迭代它的尝试。

既然您说过,“<em>我需要将字符串的这些部分作为 anIterable传递给特定的库”,因此没有通用的解决方案,因为使用的代码Iterable超出了您的控制范围。

但是,如果您是创建流的人,则可以创建一个有效的Iterable,它将在每次Iterator请求 an 时简单地重复流构造:

Iterable<String> lines = () -> "this\nthat\nthe_other".lines().iterator();

这满足了支持任意数量的迭代的期望,同时在仅遍历一次时不会消耗比单个流更多的资源。

for(var s: lines) System.out.println(s);
lines.forEach(System.out::println);
System.out.println(String.join("\n", lines));
于 2020-01-23T08:04:07.337 回答
7

tl;博士

只需投射,无需转换。

投射Stream<String>::iteratorIterable<String>.

细节

注意请参阅 Holger 的回答,解释使用流支持的危险Iterable

是的,您可以IterableStream.

解决方案很简单,但并不明显。请参阅Maurice Naftalin 的 Lambda FAQ上的这篇文章

返回 a的(superclass of )iterator方法的签名与功能接口的唯一方法匹配,因此方法引用可以用作 的实例。(这两种方法具有相同名称的事实是巧合。)BaseStreamStreamIteratorIterableStream<T>::iteratorIterable<T>

做你的输入。

String input = "this\n" +
        "that\n" +
        "the_other";
Stream<String> stream = input.lines() ;

使用方法引用生成一个Iterable<String>.

Iterable< String > iterable = stream::iterator;

测试结果。

for ( String s : iterable ) 
{
    System.out.println( "s = " + s );
}

请参阅在 IdeOne.com 上实时运行的代码

s = 这个

s = 那

s = the_other

CAVEAT谨防流式支持的风险Iterable。Holger在正确答案中进行了解释。

于 2020-01-22T23:04:58.840 回答