供应商<stream>产生空流,但作为列表,它不是空的

时间:2015-06-29 19:41:37

标签: java-8 java-stream

在我的代码中,我不得不多次遍历一堆类型为T的对象。由于某些对象可能非常大,我使用了Supplier Stream<T>而不是将它们全部收集在列表或集合中。方法如下:

private static Supplier<Stream<T>> streamSupplier(...) {
    Iterator<T> iterator = ...;
    Iterable<T> iterable = () -> iterator;
    return () -> StreamSupport.stream(iterable.spliterator(), false);
}

和代码中的其他地方

Supplier<Stream<T>> supplier = streamSupplier(...);
List<T> ts = supplier.get().collect(Collectors.toList());
return ts.isEmpty(); // <-- true

问题在于,当我通过上述方法返回的供应商上调用Supplier#get()方法时,始终为空。但是当我更改代码以返回列表时,一切正常:

private static List<T> listSupplier(...) {
    Iterator<T> iterator = ...;
    Iterable<T> iterable = () -> iterator;
    List<T> ts = Lists.newArrayList(iterable);
    return ts; // <-- is populated correctly, NOT empty
}

我认为如果我想重复使用一个流,那么使用Supplier是正确的方法(因此我不会以一个封闭的`Stream结束)。我做错了什么?

2 个答案:

答案 0 :(得分:2)

你可能想做这样的事情:

private static Supplier<Stream<T>> streamSupplier(...) {
    return () -> {
        Iterator<T> iterator = ...;
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
    };
}

这假定该行

Iterator<T> iterator = ...;

每次创建一个新的迭代器,独立于任何现有的迭代器。

另请注意,您应该调整Spliterator的创建方式,例如,大小是否已知,或者是否存在重要的排序等特征。

最后,要非常小心

Iterable<T> iterable = () -> iterator;

这接近于反模式。虽然它在类型系统中工作 - 调用生成的Iterable的iterator()方法将返回Iterator的实例 - 它通常不起作用。原因是大多数使用Iterable实例的代码假定它可以多次调用iterator()并获得独立的迭代器。这不是那样做的;它捕获迭代器并每次返回相同的 Iterator实例。这会导致与您所看到的类似的奇怪破损。

答案 1 :(得分:1)

看起来您正在尝试从同一个迭代器创建许多流。

试试这个:

Iterable<Document> docIterable = () -> ...;

...来自Iterator<Document> docIterator = ...;

另外,为什么要返回Supplier<Stream<Document>>而不只是Stream<Document>