JAVA8已经发布了八年多,但2014年发布的许多特性都延续到了2022年。其中最突出的是Java流。在这篇文章中,我们解释了什么是Java流,解释了何时使用它们。并简要介绍了常见的Java流操作。
Java中的流是什么?
Java流支持对元素流的函数式操作。流是以某种顺序应用于数据的不可变函数集合的抽象。流不是可以存储元素的集合。
流和结构之间最重要的区别是流不保存数据。例如,你不能指向流中某个元素存在的位置。你只能指定对该数据进行操作的函数。并且在流上执行操作时,会影响原流。
注意,这个文章中的流不要与Java I/O包中的流混淆,如InputStream、OutputStream等。
何时使用Java流
Java流代表了数据流动的管道和对数据进行操作的函数。在这种情况下,管道由一个流源、零个或多个中间操作以及一个终端操作组成。因此,流可以用在任何涉及数据驱动函数的应用程序中。
在下面的例子中,Java流被用作一个奇特的迭代器:
在这个例子中,我们只选择偶数值,通过使用过滤器方法,并将它们增加了一倍绘图使输入加倍的函数。这给我们提供了什么?streams API为我们提供了在各个步骤中指定数据操作序列的能力。我们不指定任何条件处理代码,我们不想编写大型复杂函数,我们不关心数据流。
事实上,我们一次只为一个数据处理步骤而烦恼:我们通过streams框架的能力自己组合函数和通过函数的数据流。上面的例子显示了你最终将在流中使用的最重要的模式之一:
将集合提升到流。
骑流:过滤值,转换值,限制输出。
组成小的个体操作。
将结果收集回具体的集合中。
流中的常见操作
在Java 8及更高版本中,你可以通过调用stream()方法轻松地从任何集合中获取流。之后,还有几个你会经常遇到的基本函数。
以下是Java流中的一些常见操作:
过滤器:返回一个新流,其中包含原始流的一些元素。它接受谓词来计算应该在新流中返回哪些元素,并删除其余的元素。在命令式代码中,我们会使用条件逻辑来指定应该发生什么如果一个元素满足条件。在功能性的风格中,我们不用费心可安装文件系统,我们过滤流,只处理我们需要的值。
地图:将流元素转换成其他东西,它接受一个应用于流中每个元素的函数,并返回参数函数产生的值的流。这是Java流API的基础。Map允许你对流中的数据执行计算。
减少:(有时也称为折叠)将流简化为单个元素。如果你想要对流中的所有整数值求和,你需要使用reduce函数。如果你想在流中找到最大值,reduce就是你的朋友。
收集:这是走出流世界并获得具体的值集合的方法,就像上面例子中的列表一样。
你不会在每次遇到流时都使用所有这些函数,但是你可以随意使用它们。
关于Java Streams API的最终想法
并行运行每个流操作存在缺陷,大多数streams实现使用默认的ForkJoinPool在后台执行操作。因此,你可以很容易地使特定的流处理稍微快一点,但是却牺牲了整个JVM的性能,甚至没有意识到这一点。
使用函数式编程解决问题需要不同的思维方式。但是通过一点试验,你就能掌握它的窍门。
通常,你可能很难找到一个实用的解决方案,但是一旦你得到了,你就会意识到它并不特别复杂。然后下一次解决类似的问题就容易多了。