为了账号安全,请及时绑定邮箱和手机立即绑定

我应该返回收藏集还是流?

我应该返回收藏集还是流?

慕后森 2019-12-10 13:08:33
假设我有一个将只读视图返回到成员列表的方法:class Team {    private List < Player > players = new ArrayList < > ();    // ...    public List < Player > getPlayers() {        return Collections.unmodifiableList(players);    }}进一步假设所有客户要做的就是立即遍历列表一次。也许将播放器放入JList之类。客户端就不能存储到列表的引用以便稍后进行检查!在这种常见情况下,我应该返回流吗?public Stream < Player > getPlayers() {    return players.stream();}还是在Java中返回流非惯用语?流是否设计为始终在创建它们的相同表达式内被“终止”?
查看完整描述

3 回答

?
芜湖不芜

TA贡献1796条经验 获得超7个赞

答案是一如既往的“取决于”。这取决于返回的集合的大小。这取决于结果是否随时间变化,以及返回结果的一致性有多重要。这在很大程度上取决于用户使用答案的方式。


首先,请注意,您始终可以从Stream中获取Collection,反之亦然:


// If API returns Collection, convert with stream()

getFoo().stream()...


// If API returns Stream, use collect()

Collection<T> c = getFooStream().collect(toList());

所以问题是,这对您的呼叫者更有用。


如果结果可能是无限的,则只有一种选择:流。


如果结果可能非常大,则您可能更喜欢Stream,因为一次实现所有可能没有任何价值,这样做可能会产生巨大的堆压力。


如果调用者要做的只是遍历它(搜索,过滤器,聚合),则您应该首选Stream,因为Stream已经内置了这些内容,因此不需要实现集合(特别是如果用户可能不处理集合的话)整个结果。)这是一个非常普遍的情况。


即使您知道用户将对其进行多次迭代或以其他方式保留它,您仍然可能想返回一个Stream,原因很简单,无论您选择放入哪个Collection(例如ArrayList)都可能不是形式,然后调用者无论如何都必须复制它。如果您返回流,则他们可以collect(toCollection(factory))按照所需的形式进行获取。


上面的“首选Stream”案例主要是因为Stream更加灵活;您可以后期绑定到您的使用方式,而不会产生将其具体化为Collection的成本和约束。


在有很强的一致性要求时,必须返回集合的一种情况是,您必须生成移动目标的一致性快照。然后,您需要将元素放入不会更改的集合中。


因此,我想说,在大多数情况下,Stream是正确的答案-它更灵活,它不会带来通常不必要的实现成本,并且可以根据需要轻松地转换为您选择的Collection。但是有时,您可能必须返回Collection(例如,由于强烈的一致性要求),或者您可能想返回Collection,因为您知道用户将如何使用它,并且这对他们来说是最方便的事情。



查看完整回答
反对 回复 2019-12-11
?
森栏

TA贡献1810条经验 获得超5个赞

与集合相反,流具有其他特征。任何方法返回的流可能是:


有限或无限

并行或顺序(具有可能影响应用程序任何其他部分的默认全局共享线程池)

有序或无序

这些差异也存在于集合中,但它们是显而易见的契约的一部分:


所有集合都有大小,Iterator / Iterable可以是无限的。

集合是显式排序或非排序的

值得庆幸的是,并行性并不是线程安全性所关心的问题。

作为流的使用者(从方法返回或作为方法参数),这是一种危险且令人困惑的情况。为了确保其算法正确运行,流的使用者需要确保算法对流的特性没有错误的假设。这是一件非常困难的事情。在单元测试中,这意味着您必须将所有要重复的测试乘以相同的流内容,但要使用


(有限,有序,顺序)

(有限,有序,并行)

(有限,无序,顺序)...

如果输入流具有破坏算法的特性,则编写方法可以保护引发IllegalArgumentException的流,因为这些属性是隐藏的。


当上述所有问题都不重要时,这仅将Stream留作方法签名中的有效选择,这种情况很少发生。


在方法签名中使用显式协定(并且不涉及隐式线程池处理)使用其他数据类型要安全得多,这使得不可能以错误的顺序,大小或并行性(和线程池使用)假设来意外处理数据。



查看完整回答
反对 回复 2019-12-11
  • 3 回答
  • 0 关注
  • 243 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信