《Java核心技术 卷Ⅱ 高级特性(原书第10版)》一1.12 约简操作

1.12 约简操作

reduce方法是一种用于从流中计算某个值的通用机制,其最简单的形式将接受一个二元函数,并从前两个元素开始持续应用它。如果该函数是求和函数,那么就很容易解释这种机制:
image

在上面的情况中,reduce方法会计算v0+v1+v2+…,其中vi是流中的元素。如果流为空,那么该方法会返回一个Optional,因为没有任何有效的结果。

注意:在上面的情况中,可以写成reduce(Integer::sum)而不是reduce((x, y) -> x+y)。

通常,如果reduce方法有一项约简操作op,那么该约简就会产生v0 op v1 op v2 op…,其中我们将函数调用op(vi, vi+1)写作vi op vi+1。这项操作应该是可结合的:即组合元素时使用的顺序不应该成为问题。在数学标记法中,(x op y) op z必须等于x op (y op z)。这使得在使用并行流时,可以执行高效的约简。
有很多种在实践中会显得很有用的可结合操作,例如求和、乘积、字符串连接、取最大值和最小值、求集的并与交等。减法是一个不可结合操作的例子,例如,(6-3)-2≠6-(3-2)。
通常,会有一个幺元值e使得e op x = x,可以使用这个元素作为计算的起点。例如,0是加法的幺元值。然后,可以调用第2种形式的reduce:
image

如果流为空,则会返回幺元值,你就再也不需要处理Optional类了。
现在,假设你有一个对象流,并且想要对某些属性求和,例如字符串流中的所有字符串的长度,那么你就不能使用简单形式的reduce,而是需要(T,T)->T这样的函数,即引元和结果的类型相同的函数。但是在这种情况下,你有两种类型:流的元素具有String类型,而累积结果是整数。有一种形式的reduce可以处理这种情况。
首先,你需要提供一种“累积器”函数(total, word) -> total + word.length()。这个函数会被反复调用,产生累积的总和。但是,当计算被并行化时,会有多个这种类型的计算,你需要将它们的结果合并。因此,你需要提供第二个函数来执行此处理。完整的调用如下:
image

注意:在实践中,你可能并不会频繁地用到reduce方法。通常,映射为数字流并使用其方法来计算总和、最大值和最小值会更容易。(我们将在1.13节中讨论数字流。)在这个特定示例中,你可以调用words.mapToInt(String::length).sum(),因为它不涉及装箱操作,所以更简单也更高效。
注意:有时reduce会显得并不够通用。例如,假设我们想要收集BitSet中的结果。如果收集操作是并行的,那么就不能直接将元素放到单个BitSet中,因为BitSet对象不是线程安全的。因此,我们不能使用reduce,因为每个部分都需要以其自己的空集开始,并且reduce只能让我们提供一个幺元值。此时,应该使用collect,它会接受单个引元:

1.一个提供者,它会创建目标类型的新实例,例如散列集的构造器。
2.一个累积器,它会将一个元素添加到一个实例上,例如add方法。
3.一个组合器,它会将两个实例合并成一个,例如addAll。
下面的代码展示了collect方法是如何操作位集的:

image

java.util.Stream 8
image

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值