Supplier <Stream> 产生空流,但作为列表,它不是空的
Supplier <Stream> yields empty stream, but as a list, it's not empty
在我的代码中,我不得不多次遍历一堆类型为 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
问题是当我通过上述方法调用return供应商的Supplier#get()
方法时,它总是是空的。但是当我将代码更改为 return 列表时,一切正常:
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
}
我认为如果我想重复使用一个流(这样我就不会以关闭的`Stream 结束),使用 Supplier
是正确的方法。我做错了什么?
您似乎正试图从同一个迭代器创建多个流。
试试这个:
Iterable<Document> docIterable = () -> ...;
...
来自 Iterator<Document> docIterator = ...;
此外,您为什么要返回 Supplier<Stream<Document>>
而不是 Stream<Document>
?
你可能想做这样的事情:
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() 方法将 return Iterator 的一个实例——但它通常不会工作。原因是大多数使用 Iterable 实例的代码都假定它可以多次调用 iterator() 并获得独立的迭代器。这不会那样做;它每次捕获 Iterator 和 returns same Iterator 实例。这将导致与您所看到的类似的奇怪破损。
在我的代码中,我不得不多次遍历一堆类型为 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
问题是当我通过上述方法调用return供应商的Supplier#get()
方法时,它总是是空的。但是当我将代码更改为 return 列表时,一切正常:
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
}
我认为如果我想重复使用一个流(这样我就不会以关闭的`Stream 结束),使用 Supplier
是正确的方法。我做错了什么?
您似乎正试图从同一个迭代器创建多个流。
试试这个:
Iterable<Document> docIterable = () -> ...;
...
来自 Iterator<Document> docIterator = ...;
此外,您为什么要返回 Supplier<Stream<Document>>
而不是 Stream<Document>
?
你可能想做这样的事情:
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() 方法将 return Iterator 的一个实例——但它通常不会工作。原因是大多数使用 Iterable 实例的代码都假定它可以多次调用 iterator() 并获得独立的迭代器。这不会那样做;它每次捕获 Iterator 和 returns same Iterator 实例。这将导致与您所看到的类似的奇怪破损。