在java中,流比循环有什么优点?

qaxu7uf2  于 2021-06-30  发布在  Java
关注(0)|答案(5)|浏览(302)

关闭。这个问题需要更加突出重点。它目前不接受答案。
**想改进这个问题吗?**通过编辑这篇文章更新这个问题,使它只关注一个问题。

三年前关门了。
改进这个问题
我在一次面试中被问到这个问题,我不相信我能给出最好的答案。我提到过你可以做一个并行搜索,空值是通过一些我不记得的方法处理的。现在我意识到我在考虑选择。我错过了什么?他们声称这是更好或更简洁的代码,但我不确定我是否同意。
考虑到这个问题的回答是多么简洁,看来这毕竟不是一个太宽泛的问题。
如果他们在面试时问这个问题,而且很明显他们是这样问的,那么除了让问题更难找到答案之外,把问题分解开来还有什么用呢?我是说,你在找什么?我可以分解问题并回答所有子问题,但然后创建一个与所有子问题链接的家长问题。。。但看起来很傻。在我们讨论这个问题时,请给我举一个不太宽泛的问题的例子。我知道没有办法只问这个问题的一部分,而仍然得到一个有意义的答案。我可以用不同的方式问同样的问题。例如,我可以问“streams的用途是什么?”或者“我什么时候使用stream而不是for循环?”或者“为什么要用streams而不是for循环?”这些都是完全相同的问题。
……还是因为有人给出了一个很长的多点答案而被认为过于宽泛?坦率地说,任何知情人士都可以用几乎任何问题做到这一点。例如,如果您碰巧是jvm的作者之一,您可能整天都在谈论for循环,而我们大多数人却不能。
“请编辑此问题,将其限制为特定问题,并提供足够详细的信息,以确定适当的答案。避免同时问多个不同的问题。请参阅“如何询问”页面,以获取有关澄清此问题的帮助。“
如下文所述,已经给出了一个充分的答案,证明有一个答案,而且很容易提供。

cx6n0qe3

cx6n0qe31#

抛开语法方面的乐趣不谈,流的设计是为了处理可能无限大的数据集,而数组、集合和几乎所有实现iterable的javase类都完全在内存中。
流的一个缺点是过滤器、Map等不能抛出选中的异常。这使得流对于中间i/o操作来说是一个糟糕的选择。

snvhrwxg

snvhrwxg2#

在序列(数组、集合、输入等)上循环,因为要对序列的元素应用某些函数。
流使您能够在序列元素上组合函数,并允许独立于具体情况实现最常见的函数(例如,Map、过滤、查找、排序、收集等)。
因此,在大多数情况下,给定一些循环任务,您可以使用流以较少的代码来表达它,即获得可读性。

rqdpfwrv

rqdpfwrv3#

有趣的是,面试问题问的是优点,而不是缺点,因为两者都有。
流是一种更具声明性的样式。或者更具表现力的风格。在代码中声明您的意图可能比描述它是如何完成的要好:

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;

说“我在做循环”。循环的目的在逻辑中埋藏得更深。
溪流通常较短。同样的例子说明了这一点。简洁并不总是更好,但如果你能同时简洁和富有表现力,那就更好了。
流与函数有很强的亲和力。Java8引入了lambda和函数接口,这为强大的技术打开了一个完整的工具箱。流提供了将函数应用于对象序列的最方便和自然的方法。
流鼓励更少的易变性。这在某种程度上与函数式编程有关——使用流编写的程序往往是不修改对象的程序。
流鼓励松散耦合。流处理代码不需要知道流的源代码,也不需要知道流的最终终止方法。
流可以简洁地表达相当复杂的行为。例如:

stream.filter(myfilter).findFirst();

乍一看似乎它过滤了整个流,然后返回第一个元素。但事实上 findFirst() 驱动整个操作,因此它在找到一个项目后高效地停止。
溪流为未来效率的提高提供了空间。一些人做了基准测试,发现内存中的单线程流 List s或数组可以比等效循环慢。这是合理的,因为有更多的对象和间接费用在发挥作用。
但溪流规模很大。除了java内置的对并行流操作的支持之外,还有一些用于分布式map reduce的库使用流作为api,因为模型适合。
缺点?
性能:a for 通过数组的循环在堆和cpu使用方面都是非常轻量级的。如果优先考虑原始速度和内存节约,那么使用流就更糟了。
熟悉度。世界上充满了经验丰富的过程程序员,他们来自许多语言背景,对他们来说循环是熟悉的,流是新奇的。在某些环境中,您希望编写这种人熟悉的代码。
认知开销。由于它的声明性,以及从下面发生的事情中增加的抽象性,您可能需要构建一个新的思维模型来描述代码与执行的关系。实际上,您只需要在出现问题时,或者需要深入分析性能或细微缺陷时才需要这样做。当它“起作用”的时候,它就起作用了。
调试器正在改进,但即使是现在,当您在调试器中单步执行流代码时,也可能比等效循环更困难,因为简单循环非常接近传统调试器处理的变量和代码位置。

ws51t4hk

ws51t4hk4#

我认为它的并行化非常容易使用。尝试用for循环并行迭代数百万个条目。我们使用许多cpu,而不是更快;因此,并行运行越容易越好,而且 Stream 这是微风。
我最喜欢的是他们的冗长。了解他们实际做什么和生产什么只需要很少的时间,而不是他们是如何做的。

qxsslcnc

qxsslcnc5#

您错误地认识到:并行操作使用 Stream s、 不是 Optional s。
您可以定义处理流的方法:将它们作为参数,返回它们,等等。您不能定义将循环作为参数的方法。这允许一次使用一个复杂的流操作并多次使用它。注意,java在这里有一个缺点:您的方法必须作为 someMethod(stream) 相对于溪流本身 stream.someMethod() ,所以把它们混合在一起会使阅读复杂化:试着看一下

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

许多其他语言(c#、kotlin、scala等)允许某种形式的“扩展方法”。
即使您只需要顺序操作,并且不想重用它们,这样您就可以使用流或循环,流上的简单操作可能对应于循环中相当复杂的更改。

相关问题