Lambdas in Java
Introduce
Lambada Expressions
lambda表达式的固定格式如下: parameter -> expression body
一个lambda表达式有如下特点:可不声明参数类型,编译器会自动推导;单个参数无需加括号,多个参数必须加括号;单条语句无需加花括号;return关键词可省略。
参考:
Lambda Expressions
Method References
方法引用有助于按照名称指向方法。其使用“::”符号描述方法引用。方法引用可以用来指出以下类型的方法:静态方法;实例方法;使用new运算符的构造器方法。
大多数引用的是静态方法,但是也有一些其它情况,主要有以下几种类型的方法引用:
Functional Interfaces
functional interfaces有着一个特定的功能展示的作用。例如:使用单个方法 compareTo 的 Comparable接口来用于比较。
参考:
Function Interfaces
Effective Java Items about Lambdas
Item42: Prefer lambdas to anonymous classes
在支持lambda之前,Java中一般用匿名函数来实现函数对象这样的功能。比如:
|
|
而用lambda表达式可以这样写比较简洁:
|
|
使用lambda表达式时,一般会省略参数的类型,因为编译器会进行自动推导类型。当编译器不能推导出类型时,需要我们显式指定。一个重要的原则就是:为了让lambda表达式更简洁,尽量省略参数类型。有时需要对返回值进行类型转换或者对整个lambda表达式进行类型转换,但是这比较少见。
和方法及类不同,lambda缺少名称和文档,如果一个运算不是很容易理解或者行数太多,那么就不要使用lambda表达式。
总而言之,目前而言,lambda表达式是表示小型函数对象的最佳方法。除非必须要创建非函数接口的类型实例,否则不要使用匿名类。
Item43: Prefer method references to lambdas
lambda表达式相较于匿名类的主要优势就是其更简洁。然而Java提供了一种比lambda表达式更为简洁的生成函数对象的方法:方法引用(method references)。使用方法引用通常会生成更短更清晰的代码。但是也有例外的情况,使用的时候可以根据具体情况选择使用lambda还是方法引用。
一般而言,方法引用提供了一种比lambda表达式更为简洁的方法。总的使用原则就是:方法引用更为简洁时就使用它,否则使用lambda。
Item44: Favor the use of standard functional interfaces
Java有了lambda之后,我们在设计API的时候就有必要随时考虑lambda。既能接受functional interface类型作为输入也要能将其作为输出。通常情况下,最好使用java.util.function.Function中的标准接口,但是极少数情况下可能还是需要我们自己设计functional interfaces。
主要有如下一些使用原则:
1、优先使用标准functional interface
2、java.util.function中有43种接口类型,比较常用的有以下6种:
3、多数标准functional interfaces只提供了对于基本类型的支持。不要试图用包装的基本类型来替代基本类型的functional interfaces。
4、使用 @FunctionalInterface注解来定义函数接口。
Streams in Java
Introduce
Streams
streams表示来自源的一系列对象,其支持聚合操作,有以下特征:
1、元素序列:stream以顺序的方式提供一组特定类型的元素。其按需获取或者计算元素。其从不存储元素。
2、源:其将Collection, Array或者IO资源作为输入。
3、聚合操作:其支持聚合操作,如filter, map, limit, reduce, find, match等。
4、流水线:大多数stream操作本身返回stream,以使得其操作可以流水线话。collect()方法是在流水线操作结束时通常存在的终端操作,用于标记流的结束。
5、自动迭代:stream通过所提供的源元素在内部执行迭代,与需要显式迭代的集合相反。
示例
可以用stream()或者parallelStream()方法生成Stream。
更多示例可参考:
Streams
Effective Java Items about Streams
Item45: Use streams judiciously
Stream API用起来非常流畅,其就是设计来将一连串的方法调用连成一个管道作为一条语句。使用得当的话,streams能将程序变得更短更清晰,而使用不当会导致程序 很难阅读和理解。
总的来说,有些任务用stream的方法完成较好,有些任务用iteration的方式完成较好。许多任务可以用两种方式的组合来更好地完成。对于两种方式之间的选择,并没有特定的方法,还是需要根据实际情况决定。如果不能确定用哪种方式更好,索性两种方式都试一下并比较再做决定。
更多具体例子可参考书籍 Effective Java 3rd edition
Item46: Prefer side-effect-free functions in streams
stream的本质是无副作用的函数对象,这适用于传递给stream的所有许多函数对象和相关的对象。每个终端操作只能用于报告由stream执行的计算的结果,而不执行计算。为了正确使用stream,我们必须熟悉collectors。最重要的收集器工厂是toList, toSet, toMap, groupingBy和joining。
一些使用原则:
1、forEach操作应该被用于报告stream的计算结果而不是执行计算。
2、为了使得使用stream的代码更具可读性,比较明智的做法是静态导入Collectors。