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

在Java中,流比循环有什么优势?

在Java中,流比循环有什么优势?

慕雪6442864 2019-12-09 15:57:43
面试中有人问我这个问题,但我不相信我给出了我能提供的最佳答案。我提到您可以进行并行搜索,并且空值是通过某种我不记得的方式处理的。现在,我意识到我在考虑选修课。我在这里想念什么?他们声称这是更好或更简洁的代码,但我不确定我是否同意。考虑到答案的简洁程度,看来这毕竟不是一个太宽泛的问题。如果他们在面试中提出这个问题,而且很明显,分解该问题的目的是什么,而不是使其很难找到答案?我的意思是,你在找什么?我可以分解问题,并回答所有子问题,但是然后创建一个带有所有子问题链接的父问题……虽然看起来很傻。当我们讨论这个问题时,请举例说明一个不太广泛的问题。我不知道只问这个问题的一部分,仍然会得到有意义的答案。我可以用不同的方式问同样的问题。例如,我可以问“流的作用是什么?” 或“何时使用流而不是for循环?” 或“为什么要麻烦流而不是for循环?” 这些都是完全相同的问题。...还是因为有人给出了很长的多点答案而被认为过于宽泛?坦率地说,任何有识之士都可以解决任何问题。例如,如果您碰巧是JVM的作者之一,那么您可能整天都在谈论for循环,而我们大多数人却无法。“请编辑问题以将其限制在一个特定的问题上,并要有足够的细节来确定适当的答案。避免一次提出多个不同的问题。请参阅“如何提出问题”页面,以帮助您弄清这个问题。”如下所述,已经给出了足够的答案,证明存在一个答案,并且很容易提供。
查看完整描述

3 回答

?
达令说

TA贡献1821条经验 获得超6个赞

有趣的是,面试问题只问优点,而不问缺点,因为两者都有。


流是一种更具声明性的样式。或更富有表现力的风格。它可以被认为是更好的声明你的代码的意图,而不是描述如何,它的完成:


 return people

     .filter( p -> p.age() < 19)

     .collect(toList());

...很清楚地说,您正在从列表中过滤匹配的元素,而:


 List<Person> filtered = new ArrayList<>();

 for(Person p : people) {

     if(p.age() < 19) {

         filtered.add(p);

     }

 }

 return filtered;

说“我正在循环”。循环的目的被深深地埋在了逻辑中。


溪流通常更短。相同的示例显示了这一点。Terser并不总是更好,但是如果您可以同时简洁和富于表现力,那就更好了。


流与功能具有很强的亲和力。Java 8引入了lambda和功能接口,从而打开了包含强大技术的整个玩具箱。流提供了将函数应用于对象序列的最方便自然的方法。


流鼓励较少的可变性。这与功能编程方面有关-使用流编写的程序往往是不修改对象的程序。


溪流鼓励松散的耦合。您的流处理代码不需要知道流的源或其最终的终止方法。


流可以简洁地表达相当复杂的行为。例如:


 stream.filter(myfilter).findFirst();

乍一看,好像它过滤了整个流,然后返回第一个元素。但是实际上findFirst()驱动了整个操作,因此在找到一项后它有效地停止了。


流为将来提高效率提供了空间。一些人进行了基准测试,发现内存中List或数组中的单线程流可能比等效循环慢。这是合理的,因为有更多的对象和开销在玩。


但是溪流规模。除了Java对并行流操作的内置支持之外,由于模型合适,因此有一些使用Streams作为API的分布式映射减少库。


劣势?


性能:for数组循环在堆和CPU使用率方面都非常轻巧。如果原始速度和内存节俭是优先考虑的事情,那么使用数据流会更糟。


熟悉。世界上到处都是经验丰富的程序程序员,来自许多语言背景,他们熟悉循环并且流是新颖的。在某些环境中,您想编写这种人熟悉的代码。


认知开销。由于它具有声明性,并且越来越多地从下面发生的事情中提取内容,因此您可能需要构建一个新的思维模型来了解代码与执行的关系。实际上,仅在出现问题或需要深入分析性能或细微的错误时才需要这样做。当它“起作用”时,它就起作用。


调试器正在改进,但是即使在现在,当您逐步调试调试器中的流代码时,它也比等效循环更难工作,因为简单的循环非常接近传统调试器所使用的变量和代码位置。


查看完整回答
反对 回复 2019-12-09
?
Helenr

TA贡献1780条经验 获得超4个赞

您认识不正确:并行操作使用Streams而不是Optionals。


您可以定义使用流的方法:将它们作为参数,返回它们,等等。您无法定义将循环作为参数的方法。这允许一次复杂的流操作并多次使用。请注意,Java在此有一个缺点:方法的调用必须与someMethod(stream)stream的方法相反stream.someMethod(),因此将它们混合会使阅读变得复杂:尝试查看操作的顺序


myMethod2(myMethod(stream.transform(...)).filter(...))

许多其他语言(C#,Kotlin,Scala等)允许某种形式的“扩展方法”。


即使当您只需要顺序操作,又不想重复使用它们,以便可以使用流或循环时,对流的简单操作也可能对应于循环中相当复杂的更改。


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

添加回答

举报

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