使用 Java 8 JDK 将 Iterable 转换为 Stream

问题描述 投票:0回答:8

我有一个返回

java.lang.Iterable<T>
的界面。

我想使用 Java 8 Stream API 操作该结果。

但是 Iterable 无法“流”。

知道如何将 Iterable 用作 Stream 而不将其转换为 List 吗?

java java-8 java-stream iterable
8个回答
697
投票

Iterable
有一个
spliterator()
方法,您可以将其传递给
StreamSupport.stream
来创建流:

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

这是一个比直接使用

spliteratorUnknownSize
更好的答案,因为它更容易并且获得更好的结果。在最坏的情况下,它是相同的代码(默认实现使用
spliteratorUnknownSize
),但在更常见的情况下,您的
Iterable
已经是一个集合,您将获得更好的分割器,从而获得更好的流性能(甚至可能是良好的并行性)。代码也更少。

如您所见,从

Iterable
获取流(另请参阅这个问题)并不是很痛苦。


95
投票

如果你可以使用Guava库,从21版本开始,你可以使用

Streams.stream(iterable)

24
投票

您可以轻松地从

Stream
Iterable
创建
Iterator
:

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

11
投票

我想建议使用 JOOL 库,它隐藏了

Seq.seq(iterable)
调用背后的 spliterator 魔法,并且还提供了一大堆额外的有用功能。


8
投票

因此,正如另一个答案提到的那样,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
  );
}

6
投票

我创建了这个类:

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)。


4
投票

解决此问题的一个非常简单的方法是创建一个扩展

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>
来进行流式传输。


0
投票

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

Iterable i = //...
Stream.ofAll(i);
© www.soinside.com 2019 - 2024. All rights reserved.