Java Stream API(下篇)

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

串联流

Java Stream接口包含一个名为concat()的静态方法,它可以将两个流连接成一个流。结果是一个新Stream,它包含第一个流的所有元素,后面跟着第二个流的所有元素。下面是一个使用Java Stream concat()方法的示例:

从数组创建流

Java Stream接口包含一个名为of()的静态方法,可以使用该方法从一个或多个对象创建一个Stream。下面是一个使用Java Stream ' ' of()方法的例子:

Stream<String> streamOf = Stream.of("One", "two", "three");
复制代码

Java Stream API Critique

在使用Apache Kafka Streams API等其他数据流API后,我对Java Stream API有一些批评,我将与您分享。它们不是重要的批评点,但当你冒险进行流处理时,它们在你的脑海中很有用。

批处理,而不是流处理

尽管名称如此,Java Stream API并不是一个真正的流处理API。Java Stream API的终端操作返回遍历流中所有元素的最终结果,并向元素提供非终端和终端操作。处理完流中的最后一个元素后,返回终端操作的结果。

只有当您知道流中的最后一个元素是什么元素时,才能在处理完流的最后一个元素后返回最终结果。了解给定元素是否是流中最后一个元素的唯一方法是,如果您正在处理具有最后一个元素批处理。相比之下,真正的流没有最后一个元素。你永远不知道给定的元素是否是最后一个。因此,不可能在流上执行终端操作。您最多只能在处理给定元素后收集临时结果,但这将是采样,而不是最终结果

Chain, Not Graph

Java Stream API的设计使Stream实例只能操作一次。换句话说,您只能向Stream添加单个非终端操作,从而生成一个新的Stream对象。您可以向生成的Stream对象添加另一个非终端操作,但不能添加到第一个。非终端Stream实例的结果结构形成一个链。

在真正的流处理API中,根流和事件侦听器通常可以形成一个图表,而不仅仅是一个链。多个侦听器可以监听根流,每个侦听器可以以自己的方式处理流中的元素,并因此转发转换后的元素。因此,每个侦听器(非终端操作)通常可以充当流本身,其他侦听器可以监听结果。这就是Apache Kafka Streams的设计方式。每个侦听器(中间流)也可以有多个侦听器。由此产生的结构形成了一个带有听众和听众的图表等。

使用流处理图而不是链,图中没有单个的最终操作。我所说的最终操作是指保证是处理链中最后一个操作。相反,可以有多个最终操作。图表中的每个“叶子”都是最终操作。

当您的流处理结构可以是具有多个最终操作的图表时,流API无法像Java Stream API那样轻松支持终端操作。为了轻松支持终端操作,必须有一个单一的最终操作来返回最终结果。基于图形的流处理API可以支持“样本”操作,要求流处理图中的每个节点提供其在内部可能持有的任何值(例如和),如果有的话(仅转换侦听器节点不会有任何内部状态)。

内部迭代,而不是外部迭代

Java Stream API是故意设计的,用于对流中的元素进行内部迭代。当在Stream上调用终端操作时,迭代将启动。事实上,为了使终端操作能够返回结果,终端操作必须启动Stream中元素的迭代。

一些基于图形的流处理API还旨在向API用户隐藏元素的迭代(例如Apache Kafka Streams和RxJava)。然而,就我个人而言,我更喜欢一种设计,即每个流节点(根流和侦听器)可以通过方法调用将元素传递给他们,并通过完整的图表传递该元素进行处理。这种设计将使测试图表中的每个侦听器更容易,因为您可以配置图表,然后将元素推送到图表中,并最终检查结果(图表的采样状态)。这种设计还将使流处理图能够通过图中的多个节点而不是根流将元素推送到其中。

Guess you like

Origin juejin.im/post/7032072938836721694