我有一个返回java.lang.Iterable<T>的接口。

我想使用Java 8流API来操作这个结果。

然而Iterable不能“流”。

任何想法如何使用Iterable作为流而不转换为列表?


当前回答

如果你碰巧使用Vavr(以前称为Javaslang),这可以很简单:

Iterable i = //...
Stream.ofAll(i);

其他回答

如果你碰巧使用Vavr(以前称为Javaslang),这可以很简单:

Iterable i = //...
Stream.ofAll(i);

所以另一个回答提到,Guava支持使用:

Streams.stream(iterable);

我想强调的是,该实现与其他答案略有不同。如果Iterable类型为Collection,则对其进行强制转换。

public static <T> Stream<T> stream(Iterable<T> iterable) {
  return (iterable instanceof Collection)
    ? ((Collection<T>) iterable).stream()
    : StreamSupport.stream(iterable.spliterator(), false);
}

public static <T> Stream<T> stream(Iterator<T> iterator) {
  return StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(iterator, 0),
    false
  );
}

解决这个问题的一个非常简单的方法是创建一个Streamable<T>接口,扩展Iterable<T>,其中包含一个默认的<T> stream()方法。

interface Streamable<T> extends Iterable<T> {
    default Stream<T> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
}

现在你的任何Iterable<T>都可以通过声明它们来实现streamable <T>而不是Iterable<T>。

There's a much better answer than using spliteratorUnknownSize directly, which is both easier and gets a better result. Iterable has a spliterator() method, so you should just use that to get your spliterator. In the worst case, it's the same code (the default implementation uses spliteratorUnknownSize), but in the more common case, where your Iterable is already a collection, you'll get a better spliterator, and therefore better stream performance (maybe even good parallelism). It's also less code:

StreamSupport.stream(iterable.spliterator(), false)
             .filter(...)
             .moreStreamOps(...);

正如你所看到的,从一个Iterable对象中获取一个流(也请参见这个问题)并不是很痛苦。

你可以很容易地从Iterable或Iterator中创建一个Stream:

public static <T> Stream<T> stream(Iterable<T> iterable) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            iterable.iterator(),
            Spliterator.ORDERED
        ),
        false
    );
}