当你处理更大的数据或无限的流时,懒惰laziness是一个真正的福音, 处理数据时,我们不确定何时使用已处理的数据。eager急切的立即处理会以牺牲性能为代价,客户端可能只是使用一小部分数据。或者,根据某些条件,客户端甚至可能不需要利用该数据。
延迟处理应该基于“ 按需处理 ”策略。
目前的趋势是大数据的并行和实时处理,数据量不断增长且高性能两种要求带来挑战,Java Collections API模型可满足未来的这种跳转,Java 8 Streams API完全基于“ 仅按流程和按需处理 ”策略,因此必然支持懒惰laziness。
在Java 8 Streams API中,管道中间的操作都是惰性的,并且其内部处理模型已经过优化,使其能够使用大量数据和高性能进行处理。让我们看一下它的例子:
//Created a Stream of a Students List |
输出:
1 sec |
这里有一个在流上调用的Map操作,然后我们将延迟5秒,然后调用收集操作(终端操作)。为了证明懒惰,我们延迟了5秒。
性能优化:
如上所述,设计流的内部处理模型以优化处理流程。在处理流中,我们通常最终创建管道的各种中间操作和终端操作。各种中间操作通常会可能合并在一次性通过处理。
List < String > ids = students.stream() |
输出:
filter - 8 |
上面的例子演示了这种行为,我们有两个中间操作,即map和filter。输出显示,它们都不会在可用流的整个大小上独立执行。
首先,id-8通过filter并立即移动到map。id-9的情况也是如此,而id-10没有通过filter检查。我们可以看到id-8,一旦通过过filter就立即可用于map操作,无论在filter之前还有多少元素仍然在流中排列。
短路方法:
Java 8 Streams API借助于短路操作优化了流处理。短路方法一旦满足条件就结束流处理。在通常的短路操作中,一旦满足条件,就会中断所有处于管道之前的中间操作。一些中间操作和终端操作具有此行为。
要查看它的工作原理,请尝试以下示例字符串名称列表:
//Somewhere down the line |
操作代码见下面:第一个流操作是(实际上没有意义)map,它以大写形式返回名称。第二个操作是filter,它只返回以“B”开头的名称。现在某个地方,如果我们通常调用它上面的Collect操作,map和filter是否看到处理列表中的所有名称?
//List of names |
但是如果我们在Collect之前设置limit操作,则输出会发生显着变化。
输出:
In map - barry |
我们可以清楚地看到limit(虽然它最近从其他地方调用,它是管道中的最后一个中间操作)对map和过滤操作有影响。整个管道说,我们想要前两个以字母“B”开头的名字。一旦管道处理以“B”开头的前两个名称,map和过滤器甚至不处理其余的名称。
现在,这可以证明是一个非常巨大的性能提升。考虑一下,如果我们的列表包含几千个名称,并且我们只想要匹配某个过滤条件的前几个名称,那么一旦我们得到预期的元素,就会跳过其余元素的处理。
anyMatch,allMatch,noneMatch,findFirst,findAny,limit和sub-stream等操作是Steams API中的这种短路方法。