Java 聚合函数&;行为-并行流

Java 聚合函数&;行为-并行流,java,java-8,functional-programming,java-stream,Java,Java 8,Functional Programming,Java Stream,下面是一个使用 聚合函数(过滤器/映射/排序) & 行为(this::大写) & 终端操作(forEach) 对于给定的流(stream.of(…)) 为了避免在并行流中产生竞争条件,我了解到,我们需要额外的努力来明确地使行为在没有副作用(无状态)的情况下工作,如下所示 String capitalize(String s) { if (s.length() == 0) return s; return s.substring(0, 1)

下面是一个使用

聚合函数(
过滤器
/
映射
/
排序

&

行为(
this::大写

&

终端操作(
forEach

对于给定的流(
stream.of(…)


为了避免在并行流中产生竞争条件,我了解到,我们需要额外的努力来明确地使行为在没有副作用(无状态)的情况下工作,如下所示

String capitalize(String s) {
        if (s.length() == 0)
            return s;
        return s.substring(0, 1)
            .toUpperCase()
            + s.substring(1)
            .toLowerCase();
聚合函数只对从流生成的每个元素应用行为


作为从流生成的元素(一次一个),没有非瞬态存储


没有任何额外的努力,聚合函数总是纯函数,没有任何副作用吗?这不会在并行流中产生竞争条件

流API的一个关键点是,只要您的行为参数满足标准,所有操作都支持正确的并行处理。或者,如前所述:

相似 具有显式for循环的处理元素本质上是串行的。流通过将计算重新构造为聚合操作的管道,而不是每个元素上的命令操作,从而促进并行执行。所有流操作都可以串行或并行执行

除了被明确标识为不确定的操作,例如
findAny()
,流是顺序执行还是并行执行都不应改变计算结果

大多数流操作接受描述用户指定行为的参数,这些参数通常是lambda表达式。为了保持正确的行为,这些行为参数必须是无干扰的,并且在大多数情况下必须是无状态的。此类参数始终是函数接口(如Function)的实例,通常是lambda表达式或方法引用


注意,术语聚合操作更一般,适用于整个流操作,包括中间操作和终端操作。关于
map
filter
的内容也适用于
reduce
;还原函数应该是无副作用和无状态的。请注意,虽然
collect
包含可变状态,但它是本地的,并且仍然满足非干扰标准。如果无状态,您仍然可以从外部查看
collect
操作

您必须查看特定终端操作的文档,以了解并行执行可能会如何影响结果,如前面提到的
findFirst
findAny
之间的差异。在您的情况下,这是有问题的,因为它可能会同时无序地调用使用者,因此无法保证元素是按照前面的
排序的
步骤所施加的顺序打印的。您应该在此处使用
forEachOrdered

顺便说一句,您可以将
方法
static
大写,以强调它不依赖于
实例的状态。或者将其简化为lambda表达式,

s->s.isEmpty()?s:s.substring(0,1).toUpperCase()+s.substring(1).toLowerCase()

流API的一个关键点是,只要行为参数满足标准,所有操作都支持正确的并行处理。或者,如前所述:

相似 具有显式for循环的处理元素本质上是串行的。流通过将计算重新构造为聚合操作的管道,而不是每个元素上的命令操作,从而促进并行执行。所有流操作都可以串行或并行执行

除了被明确标识为不确定的操作,例如
findAny()
,流是顺序执行还是并行执行都不应改变计算结果

大多数流操作接受描述用户指定行为的参数,这些参数通常是lambda表达式。为了保持正确的行为,这些行为参数必须是无干扰的,并且在大多数情况下必须是无状态的。此类参数始终是函数接口(如Function)的实例,通常是lambda表达式或方法引用


注意,术语聚合操作更一般,适用于整个流操作,包括中间操作和终端操作。关于
map
filter
的内容也适用于
reduce
;还原函数应该是无副作用和无状态的。请注意,虽然
collect
包含可变状态,但它是本地的,并且仍然满足非干扰标准。如果无状态,您仍然可以从外部查看
collect
操作

您必须查看特定终端操作的文档,以了解并行执行可能会如何影响结果,如前面提到的
findFirst
findAny
之间的差异。在您的情况下,这是有问题的,因为它可能会同时无序地调用使用者,因此无法保证元素是按照前面的
排序的
步骤所施加的顺序打印的。您应该在此处使用
forEachOrdered

顺便说一句,您可以将
方法
static
大写,以强调它不依赖于
实例的状态。或者将其简化为lambda表达式,

s->s.isEmpty()?s:s.substring(0,1).toUpperCase()+s.substring(1).toLowerCase()

您可以编写
过滤器/map/sorted
也可以作为有状态的,但在函数方面不鼓励这样做,也不太好programming@Saravana当数据是从一个流(一次一个)输入的,而不是您的本地缓冲区(列表/任何…)时,为什么
String capitalize(String s) {
        if (s.length() == 0)
            return s;
        return s.substring(0, 1)
            .toUpperCase()
            + s.substring(1)
            .toLowerCase();