我有一个返回
java.lang.Iterable<T>
的界面。
我想使用 Java 8 Stream API 操作该结果。
但是 Iterable 无法“流”。
知道如何将 Iterable 用作 Stream 而不将其转换为 List 吗?
Iterable
有一个 spliterator()
方法,您可以将其传递给 StreamSupport.stream
来创建流:
StreamSupport.stream(iterable.spliterator(), false)
.filter(...)
.moreStreamOps(...);
这是一个比直接使用
spliteratorUnknownSize
更好的答案,因为它更容易并且获得更好的结果。在最坏的情况下,它是相同的代码(默认实现使用 spliteratorUnknownSize
),但在更常见的情况下,您的 Iterable
已经是一个集合,您将获得更好的分割器,从而获得更好的流性能(甚至可能是良好的并行性)。代码也更少。
如您所见,从
Iterable
获取流(另请参阅这个问题)并不是很痛苦。
如果你可以使用Guava库,从21版本开始,你可以使用
Streams.stream(iterable)
您可以轻松地从
Stream
或 Iterable
创建 Iterator
:
public static <T> Stream<T> stream(Iterable<T> iterable) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
iterable.iterator(),
Spliterator.ORDERED
),
false
);
}
我想建议使用 JOOL 库,它隐藏了
Seq.seq(iterable)
调用背后的 spliterator 魔法,并且还提供了一大堆额外的有用功能。
因此,正如另一个答案提到的那样,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
);
}
我创建了这个类:
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)。
解决此问题的一个非常简单的方法是创建一个扩展
Streamable<T>
的 Iterable<T>
接口,其中包含 default <T> stream()
方法。
interface Streamable<T> extends Iterable<T> {
default Stream<T> stream() {
return StreamSupport.stream(spliterator(), false);
}
}
现在,您的任何
Iterable<T>
都可以轻松地通过声明它们 implements Streamable<T>
而不是 Iterable<T>
来进行流式传输。
如果您碰巧使用 Vavr(以前称为 Javaslang),这可以很简单:
Iterable i = //...
Stream.ofAll(i);