在我的代码中,我不得不多次遍历一堆类型为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结束)。我做错了什么?
答案 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>
?