在Java中,流比循环有什么优势?
我在一次采访中被问到这个问题,我不相信我给出了最好的答案。我提到可以进行并行搜索,空值是通过一些我不记得的方法处理的。现在我意识到我在考虑选择。我错过了什么?他们声称这是更好或更简洁的代码,但我不确定我是否同意在Java中,流比循环有什么优势?,java,loops,java-8,java-stream,Java,Loops,Java 8,Java Stream,我在一次采访中被问到这个问题,我不相信我给出了最好的答案。我提到可以进行并行搜索,空值是通过一些我不记得的方法处理的。现在我意识到我在考虑选择。我错过了什么?他们声称这是更好或更简洁的代码,但我不确定我是否同意 考虑到它的回答是多么简洁,这似乎毕竟不是一个太宽泛的问题 如果他们在面试时问这个问题,很明显他们是这样问的,那么把问题分解除了让问题更难找到答案之外,还有什么用呢?我是说,你在找什么?我可以将问题分解并回答所有的子问题,然后创建一个带有所有子问题链接的家长问题。。。不过看起来很傻。在
考虑到它的回答是多么简洁,这似乎毕竟不是一个太宽泛的问题
如果他们在面试时问这个问题,很明显他们是这样问的,那么把问题分解除了让问题更难找到答案之外,还有什么用呢?我是说,你在找什么?我可以将问题分解并回答所有的子问题,然后创建一个带有所有子问题链接的家长问题。。。不过看起来很傻。在我们讨论这个问题时,请给我举一个不太宽泛的问题的例子。我知道没有办法只问这个问题的一部分,而仍然得到一个有意义的答案。我可以用不同的方式问完全相同的问题。例如,我可以问“流的用途是什么?”或者“我什么时候用流代替For循环?”或者“为什么要用流代替For循环?”这些都是完全相同的问题 ……还是因为有人给出了一个很长的多点答案而被认为过于宽泛?坦率地说,任何有知识的人都可以用几乎任何问题做到这一点。例如,如果您碰巧是JVM的作者之一,您可能会整天谈论for循环,而我们大多数人却不能 “请编辑该问题,将其限制为特定问题,并提供足够的详细信息,以确定适当的答案。避免一次提出多个不同的问题。请参阅“如何提问”页面以获取澄清此问题的帮助。” 如下文所述,已经给出了一个充分的答案,证明有一个答案,而且很容易提供
流
s,而不是可选
ssomeMethod(stream)
,而不是stream自己的stream.someMethod()
,因此混合使用它们会使阅读变得复杂:试着在
myMethod2(myMethod(stream.transform(...)).filter(...))
许多其他语言(C#、Kotlin、Scala等)允许某种形式的“扩展方法”因此,在大多数情况下,给定一些循环任务,您可以使用较少的代码使用流来表达它,也就是说,您获得了可读性有趣的是,面试问题询问了优点,而没有问缺点,因为两者都有 流是一种更具声明性的样式。或者更具表现力的风格。在代码中声明您的意图可能比描述它是如何完成的要好:
return people
.filter( p -> p.age() < 19)
.collect(toList());
乍一看似乎它过滤了整个流,然后返回第一个元素。但事实上,findFirst()
驱动整个操作,因此它在找到一个项目后会有效地停止
数据流为未来的效率提升提供了空间。一些人进行了基准测试,发现内存List
s或数组中的单线程流可能比等效循环慢。这是合理的,因为有更多的对象和间接费用在发挥作用
但溪流规模很大。除了Java内置的对并行流操作的支持外,还有一些使用流作为API的分布式map reduce库,因为该模型非常适合
缺点?
性能:通过数组的循环在堆和CPU使用方面都非常轻量级。如果优先考虑原始速度和内存节约,那么使用流就更糟
熟悉性。世界上到处都是经验丰富的程序程序员,他们来自许多语言背景,对他们来说循环是熟悉的,流是新奇的。在某些环境中,您希望编写这种人熟悉的代码
认知开销。由于它的声明性性质,以及从底层发生的事情中增加的抽象性,您可能需要构建一个新的思维模型来描述代码与执行之间的关系。实际上,您只需要在出现问题时,或者需要深入分析性能或细微缺陷时,才需要这样做。当它“起作用”时,它就起作用了
调试器正在改进,但即使是现在,当您在调试器中单步执行流代码时,也可能比等效循环更困难,因为简单循环非常接近传统调试器使用的变量和代码位置。语法乐趣除外,流被设计用于处理可能无限大的数据集,而数组、集合和几乎所有实现Iterable的JavaSE类都完全在内存中
流的一个缺点是过滤器、映射等不能抛出已检查的异常。这使得一条流成为一个糟糕的选择
List<Person> filtered = new ArrayList<>();
for(Person p : people) {
if(p.age() < 19) {
filtered.add(p);
}
}
return filtered;
stream.filter(myfilter).findFirst();