return 一个 Stream<T> 的方法安全吗?

Is it safe for a method to return a Stream<T>?

我有这样一种情况,我正在读取数据库并返回 List<String>,其中每个字符串都根据某些条件被选择并添加到列表中。方法签名是:

public List<String> myMethod(String query, int limit)

第二个参数提供返回列表大小的上限(设置 limit=-1 将取消任何大小限制)。为避免使此方法占用大量内存,我编写了一个 returns Stream<String> 的等效方法,而不是列表。 (注意:我不需要随机访问返回的元素或任何其他特定于列表的功能。

但是,我对返回 Stream<> 有点怀疑,尤其是因为该方法是 public。 public 方法在 Java 中返回 Stream<> 是否安全?

不仅安全,还是recommended首席Java架构师

特别是如果您的数据是 I/O-based,因此在调用 myMethod 时尚未在内存中具体化,强烈建议 return 使用 Stream 而不是 List .客户端可能只需要消费其中的一部分,或者聚合成一些固定大小的数据。因此,您有机会从 O(n) 内存需求变为 O(1)。

请注意,如果并行化对于您的用例也是一个有趣的想法,建议您使用自定义拆分器,其拆分策略适应 I/O 数据源的顺序性质。在这种情况下,我可以推荐 a blog post of mine,它提供了这样一个拆分器。

我认为默认情况下,您应该避免在 public 方法接口中使用 Stream,因为使用它们很危险,请参阅

基本上,调用您的方法并获取流的客户端必须确保当您的方法实现更改 returned 流的特征时,它们的算法不会中断(或中断它们的集成测试).那是一件很难做到的事情(因为流的特性很容易忘记)也是一件容易忘记的事情。

因此,如果您 return 的数据尚未具体化并且您想将其留给您的客户来决定如何具体化,我什至只会将 Stream 视为 return 值。但即便如此,Iterable 或 Iterator 似乎是更好的选择,因为它们没有流所具有的不必要的并行处理包袱,而防御性编程需要防范。

例如,当 returning 一个 List 时,您的客户知道 returned 数据类型是有限且有序的,并且对其进行并行迭代并不奇怪 运行在 ForkJoinPool 上可能会破坏您的整个应用程序。使用 Stream,您必须调用 sequential() 来防止这种可能性。

如果数据源在使用后需要关闭,我更喜欢 InputStream 的变体而不是 Stream,因为实现者会清楚地记住他们需要关闭流(并且静态检查器会提醒他们)。