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

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

然而Iterable不能“流”。

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


当前回答

我创建了这个类:

public class Streams {
    /**
     * Converts Iterable to stream
     */
    public static <T> Stream<T>  streamOf(final Iterable<T> iterable) {
        return toStream(iterable, false);
    }

    /**
     * Converts Iterable to parallel stream
     */
    public static <T> Stream<T> parallelStreamOf(final Iterable<T> iterable) {
        return toStream(iterable, true);
    }

    private static <T> Stream<T> toStream(final Iterable<T> iterable, final boolean isParallel) {
        return StreamSupport.stream(iterable.spliterator(), isParallel);
    }
}

我认为它是完全可读的,因为您不必考虑分裂器和布尔值(isParallel)。

其他回答

我想建议使用JOOL库,它隐藏了Seq.seq(iterable)调用背后的分割器魔法,还提供了一大堆额外的有用功能。

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对象中获取一个流(也请参见这个问题)并不是很痛苦。

所以另一个回答提到,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>。

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

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