使用Java 8 JDK将Iterable转换为Stream

ray*_*man 402 java iterable java-8 java-stream

我有一个返回的界面java.lang.Iterable<T>.

我想使用Java 8 Stream API来操纵该结果.

但是Iterable不能"流".

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

Bri*_*etz 545

有一个比spliteratorUnknownSize直接使用更好的答案,这更容易,并获得更好的结果. Iterable有一个spliterator()方法,所以你应该用它来获得你的分裂器.在最坏的情况下,它是相同的代码(默认实现使用spliteratorUnknownSize),但在更常见的情况下,你Iterable已经是一个集合,你将获得一个更好的分裂器,因此更好的流性能(甚至可能是良好的并行性).它的代码也少了:

StreamSupport.stream(iterable.spliterator(), false)
             .filter(...)
             .moreStreamOps(...);
Run Code Online (Sandbox Code Playgroud)

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

  • `Stream`上的静态方法本来不错,例如`Stream.ofIterable(iterable)`. (102认同)
  • @robinst这不是一个遗漏; 这是一个刻意(并且备受争议的)选择.挑战在于,如果存在这种情况,在不理解随之而来的权衡的情况下实现它就太容易了.因为Iterable是如此抽象,所以这种方法会导致性能最差的流(没有并行支持,没有大小信息或特征(用于优化执行选择)).在整个生态系统中强制使用更好的API以获得更好的API.这是"对XYZ代码最有效"与"对所有Java代码最有效"的权衡. (52认同)
  • @BrianGoetz看起来大多数人都没有达到理解你上面所说的水平或者不在乎.他们只想通过调用简单的API来编写简单的代码.另一方面,那些事情(并行......)对于大多数日常可迭代操作可能并不重要. (8认同)
  • @qualidafial请参阅http://stackoverflow.com/questions/23114015/why-does-iterablet-not-provide-stream-and-parallelstream-methods. (6认同)
  • 根据你的解释,我很好奇为什么我们得到Collection.stream()而不是Iterable.stream().似乎省略Iterable.stream()(或Stream.ofIterable())的推理同样适用于Collection.stream(). (2认同)
  • 根据到目前为止给出的解释,我希望有 Stream.ofIterable(Iterable&lt;T&gt; iterable, boolean parallel) 和 Stream.ofIterable(Iterable&lt;T&gt; iterable),默认为非并行项目流。更一般地说,StreamSupport 助手应该在 Stream 类中。 (2认同)

num*_*ro6 62

如果您可以使用Guava库,那么从版本21开始,您就可以使用

Streams.stream(iterable)
Run Code Online (Sandbox Code Playgroud)

  • @JacobvanLingen那将从iterable(1遍历+内存存储)创建一个新的List. (16认同)
  • 或者,如果您使用的是旧版本,请使用Lists.newArrayList(Iterable)。 (2认同)

nos*_*sid 22

您可以轻松地创建Stream出的Iterable还是Iterator:

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

  • 是..但那会开始混乱我的代码. (4认同)
  • 你必须编写一次这个函数,然后调用它.为什么调用`stream(...)`会使你的代码混乱? (2认同)

Sha*_*gie 9

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


g-t*_*g-t 5

我创建了这个类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Ale*_*lex 5

So as another answer mentioned Guava has support for this by using:

Streams.stream(iterable);
Run Code Online (Sandbox Code Playgroud)

I want to highlight that the implementation does something slightly different than other answers suggested. If the Iterable is of type Collection they cast it.

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
  );
}
Run Code Online (Sandbox Code Playgroud)