列表流和feed流
开幕式免责声明:这并不总是一个好主意。 我将介绍这个想法,以及为什么它是一个好主意的一些原因,但随后我将讨论一些不太理想的实例。
懒惰
如您所知,我在Python中的学习几乎和在Java中一样。 我一发现Python就很喜欢生成器。 它们允许对集合执行延迟操作,因此您可以传递迭代器/生成器,直到最终真正需要这些操作的最终结果–而不影响原始集合(在大多数情况下;但您不太可能意外影响它)。
我真的很喜欢这个主意。 懒惰使您几乎不需要做任何工作,直到需要结果为止,而且还可以做到这一点,因此不会有无用的内存来存储中间集合。
懒于Java
Java也有迭代器,但没有迭代器。 但是,对于集合的惰性操作,它确实具有与之相当相似的功能: Stream
。 尽管不像Python中的生成器那样通用,但Stream
基本上可以以相同的方式使用。
绕过溪流
在很多情况下,您应该返回Stream
而不是返回的List
(或其他集合)。 这不仅为您提供了一些懒惰的好处,还为您做了一些事情。
如果返回对象的接收者希望将其collect()
放入您计划返回的List
之外的其他东西,或者他们希望以您从未想到的方式来reduce()
它,则可以给他们提供Stream
而不必担心。 然后,他们可以通过一两个Stream
方法调用来获得所需的内容。
对此有什么不好
当Stream
像集合一样传递时,存在一个很难解决的问题:它们是一次性使用的。 这意味着,如果下面的一个函数想要使用Stream
而不是List
,那么它就不容易做到,因为它需要使用List
分别做两件事。
public static List normalize(List input) {int total = input.stream().mapToInt(i -> i).sum();return input.stream().map(i -> i * 100 / total).collect(Collectors.toList());
}
为了接收Stream
,您需要collect()
它,然后在其上运行两个操作。
public static Stream normalize(Stream input) {List inputList = input.collect(Collectors.toList());int total = inputList.stream().mapToInt(i -> i).sum();return inputList.stream().map(i -> i * 100 / total);
}
这稍微违反了传递Stream
的目的。 这并不可怕,因为我们正在尝试使用Stream
的“最终”结果。 除了不是最终结果。 这是中间结果,用于计算下一个Stream
输出。 它创建了浪费内存的中间集合。
围绕此问题有很多方法,类似于该“文章”的解决方法,但是它们要么实现起来很复杂,要么容易出现用户错误。 我猜想只使用我向您展示的第二种方法是可以的,因为与第一种方法相比,它仍然可能有相当不错的性能提升,但这使我感到烦恼。
有趣(但可能有点傻)的选择
如果您熟悉我的文章,您可能会觉得本文与我前段时间写的有关使用decorator转换集合的文章背道而驰 。 从技术上讲,这篇文章确实认为这是一个相当幼稚的想法,特别是因为该想法是受Stream
启发的。 但是,与本文中介绍的Stream
的想法相比,装饰器的想法有一个主要好处:您可以一次又一次地遍历装饰的集合。 它的效率可能不如Stream
,特别是因为我不确定如何并行化它,但是它肯定具有重用性。
我有机会再次研究这个想法,看看是否可以找到一种更好的方法来实现,但是我对此表示怀疑。
奥托罗
所以,那是我的主意。 您可以选择接受或保留它。 我不确定这在典型项目中有用的频率,但是我想我将在当前和将来的项目中尝试一下。 谢谢阅读。 如果您对此有意见,请在下面评论,并让我知道。
翻译自: https://www.javacodegeeks.com/2015/02/pass-streams-instead-of-lists.html
列表流和feed流