使用Java 8 JDK将Iterable转换为Stream


418

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

我想使用Java 8 Stream API处理该结果。

但是Iterable无法“流式传输”。

任何想法如何将Iterable用作流而不转换为List?


2
如果可以迭代,为什么不简单地使用循环来检查其条件或值呢?
Afzaal Ahmad Zeeshan 2014年

26
@AfzaalAhmadZeeshan,因为溪流要好得多
Sleiman Jneidi 2014年

1
如我所说,我需要对该列表进行一些操作(过滤器,映射)。我想使用新的Java 8 JDK API-> Stream。但是Iterable不是“ SteamAble”
rayman

似乎很奇怪,myIterable.stream()不存在!
Josh M.

7
@Guillaume:是的,但是Stream.of(iterable)产生了Stream<Iterable<Object>>
马提亚斯·布劳恩

Answers:


571

有一个比spliteratorUnknownSize直接使用更好的答案,这既简单又得到更好的结果。 Iterable有一个spliterator()方法,所以您应该使用该方法来获取分离器。在最坏的情况下,它是相同的代码(默认实现使用spliteratorUnknownSize),但是在更常见的情况下,您Iterable已经是一个集合,您将获得更好的分离器,从而获得更好的流性能(甚至可能具有良好的并行性)。它的代码也更少:

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

如您所见,从中获取数据流Iterable(另请参见此问题)并不是很痛苦。


109
上的静态方法Stream会很好,例如Stream.ofIterable(iterable)
罗宾斯特2015年

59
@robinst这不是遗漏;这是一个经过深思熟虑的选择。面临的挑战是,如果不存在这种权衡,那么在不了解其权衡取舍的情况下,实现起来就太容易了。因为Iterable非常抽象,所以这种方法将导致性能最差的流(没有并行支持,没有大小信息或特性(用于优化执行选择))。强迫更多的思考会在整个生态系统中产生更好的API。这是“对XYZ代码最好的”与“对所有Java代码最好的”的权衡。
Brian Goetz

2
根据您的解释,我很好奇为什么我们有Collection.stream()但没有Iterable.stream()。似乎省略Iterable.stream()(或Stream.ofIterable())的原因同样适用于Collection.stream()。
qualidafial


11
@BrianGoetz看来大多数人都不了解您上面所说的内容或不在乎。他们只想通过调用简单API来编写简单代码。另一方面,那些事情(并行...)对于大多数日常可迭代操作可能并不重要。
user_3380739 '16


23

您可以轻松地StreamIterable或中创建一个Iterator

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

2
您只需编写一次此函数,然后调用它即可。为什么调用stream(...)会使您的代码混乱?
gexicide

1
想要做到这一点内联简短而优雅..对了,我可以编写一次此函数..但是我正在删除代码(而不是添加代码)。无论如何,这个答案是正确的,因为那是转换它的方法。
雷曼2014年

静态导入表示功能。简短而优雅。(尽管不一定透明)
aepurniet 2014年

9

我想建议使用JOOL库,它在Seq.seq(iterable)调用后面隐藏了分隔符魔术,并且还提供了许多其他有用的功能。


7

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

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);
    }
}

我认为它是完全可读的,因为您不必考虑分隔符和布尔值(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);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.