第七章 Lambda和Stream

第四十二条:Lambda优于匿名类

删除所有lambda参数的类型吧,除非他们的存在能够使程序变得更加清晰。

Lambda没有名称和文档,如果一个计算本身不是自描述的,或者超出了几行,那就不要把他放在一个lambda中。

Lambda限于函数接口,如果想创建抽象类的实例,可以用匿名类来完成,而不是用lambda。同样的,可以用匿名类为带有多个抽象方法的接口创建实例。最后一点,lambda无法获得对自身的引用。如果需要从函数对象的主体内部访问它,就必须使用匿名类。

Lambda与匿名类共享你无法可靠的通过实现来序列化和反序列化的属性,因此,尽可能不要(除非迫不得已)序列化一个Lambda。如果想要可序列化的函数对象,就使用静态嵌套类的实例。

第四十三条:方法引用优先于lambda

方法带的参数越多能用方法引用消除的样板代码,但在有些lambda中,即便它更长,但你选择的参数名称提供了非常有用的文档信息,也会使得lambda的可读性更强,并且比方法引用更易于维护。

只要方法引用能做的事,就没有lambda不能完成的(只有一种情况例外。)

有时lambda也会比方法引用更加简短明了。

那个更加简洁更加清晰,就用哪个。

第四十四条:坚持使用标准的函数接口

只要标准的函数接口能够满足需求,通常应该优先考虑,而不是专门再构建一个新的函数接口。这样会使API能够满足需求,通过减少他的概念内容,显著的提升操作性优势,因为许多标准的函数接口都提供了有用的默认方法。

千万不要用带包装类型的基础函数接口来代替基本函数接口。可能会导致性能问题。

什么时候应该自己编写接口?
如果没有任何标准的函数接口能够满足你的需求之时。

函数接口应该具备的特征:
通用,并且将受益于描述性的名称。
具有与其相关联的严格的契约。
将受益于定制的缺省方法。

必须始终用@FunctionalInterface注解对自己编写的函数接口进行标注。

不要再相同的函数位置,提供不同的函数接口来进行多次重载的方法,否则可能在客户端导致歧义。

第四十五条:谨慎使用Stream

一个Stream pipeline 包含一个源Stream,接着是0个或者多个中间操作和一个终止操作。

滥用Stream会使程序代码更难以读懂和维护。

在没有显式类型的情况下,仔细命名lambda参数,这对于Stream pipeline的可读性至关重要。

在Stream pipeline中使用helper方法,对于可读性而言,比在迭代化代码中更为重要。因为pipeline缺乏显式的类型信息和具名临时变量。

最好避免利用Stream来处理char值。

重构现有代码来使用Stream,并且只在必要的时候才在新代码中使用。

从代码块中,可以读取或者修改范围内的任意局部变量,从Lambda则只能读取final或者有效的final变量,并且不能修改任何local变量。
从代码块中,可以从外围方法中return、break或continue外围循环,或者抛出该方法声明要抛出的人任何受检异常,从Lambda中则完全无法完成这些事情。

Stream能完成的工作:
统一转换元素的序列、过滤元素的序列、利用单个操作合并元素的顺序、将元素的序列存放到一个集合中、搜索满足某些条件的元素的序列。

Stream很难完成的一件事:同时从一个pipeline的多个阶段去访问相应的元素。最好的解决方法是:当需要访问较早阶段的值时,将映射颠倒过来。

第四十六条:优先选择Stream中无副作用的函数

Stream范型最重要的部分是把计算构造成一系列变形,每一级结果都尽可能靠近上一级结果的纯函数。纯函数是指结果只取决于输入的函数:它不依赖任何可变的状态,也不更新任何状态。

Foreach操作应该只用于报告Stream计算的结果,而不是执行计算。

静态导入Collectors的所有成员是惯例也是明智的,因为这样可以提升Stream pipeline的可读性。

第四十七条:Stream要优先用Collection作为返回类型

对于公共的、返回序列的方法,Collection或者适当的子类型通常是最佳的返回类型。

千万别在内存中保存巨大的序列,将他作为集合返回即可。

总而言之,在编写一系列元素的方法时,要记住有些用户可能想要当作Stream处理,而其他用户可能想要迭代。要尽量两边兼顾。如果可以返回集合,就返回集合。如果集合中已经有元素,或者序列中的元素数量很少,足以创建一个新的集合,那么就返回一个标准的集合,如ArrayList。否则,就要考虑实现一个定制的集合,如幂集范例中所示。如果无法返回集合,就返回Stream或者Iterable,感觉哪一种更自然即可。如果在未来的Java发行版本中,Stream接口声明被修改成扩展了Iterable接口,就可以放心的返回Stream了,因为他们允许进行Stream处理和迭代。

第四十八条:谨慎使用Stream并行

即便在最佳环境下,如果源头是来自Stream.iterable,或者使用了中间操作的limit,那么并行pipeline也不可能提升性能。

千万不要任意的并行Stream pipeline。

在Stream上通过并行获得的性能,最好是通过ArrayList、HashMap、HashSet和ConcurrentHashMap实例,数组,int范围和long范围等。这些数据结构的共性是,都可以被精确、轻松的分成任意大小的子范围,使并行线程中的分工变得更加轻松。这些数据共有的另一个重要特性是,在进行顺序处理时,他们提供了优异的引用局部性:序列化的元素引用一起保存在内存中。

Stream pipeline的终止操作本质上也影响了并发执行的效率。

并行Stream不仅可能降低性能,包括活性失败,还可能导致结果出错,以及难以预计的行为(如安全性失败)。
安全性失败可能是因为并行的pipeline使用了映射、过滤器或者程序员自己编写的其他函数对象。

在适当的条件下,给Stream pipeline添加parallel调用,确实可以在多处理器核的情况下实现近乎线性的倍增。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值