Lambda真是极好的!使用Lambda先从重构旧代码开始。《Java 8实战》对其进行了讲解,本章将按照此书的脉络进行组织,对相关章节进行复习总结。
改善代码的可读性
利用Lambda表达式可以写出更简洁、更灵活的代码。
匿名类 PK Lambda
在很多场景中,匿名类都能被Lambda取代,但在这之前,需要了解两者之间的三点不同。
this & super
在匿名类中,this代表的是类本身,而在Lambda中,代表的是宿主类。
字段隐藏
我们都知道,Java的动态分派体现在方法的调用上,字段不存在“重写”只能靠隐藏。如果在一个方法中出现下列代码:
|
|
编译器就会报错:Variable ‘a’ is already defined in the scope,而在匿名类中不会出现这样的问题,所以Lambda不能做字段隐藏。
方法重载
方法重载时,Lambda会遇到引用不明的问题,看下面的代码,它构造了一个函数式接口,并添加两个重载方法:
|
|
在main方法中调用doSomeThing(() -> System.out.println());
编译器会提示说对doSomeThing的引用不明确,解决办法是采用显示类型转换:doSomeThing((Task) () -> System.out.println());
。
转换为方法引用
方法引用可以增加代码的可读性,能直观的表达代码的意图,格式为[类名]::[方法名]。
尽量考虑静态辅助方法,比如comparing、maxBy,这些方法设计之初就考虑了会结合方法引用一起使用。
增加代码的灵活性
行为参数化
可以帮助程序员淡定的面对需求变化,这里介绍两种通用模式:有条件执行和环绕执行。
有条件延迟执行
Lambda表达式是惰性求值的,这有利于行为参数化,所谓行为参数化,我的理解就是作为行参传入时只做行为描述,并不执行具体方法,仔细看下面的例子:
|
|
getNumber01和getNumber02是两个静态方法,它们是参数传入的方法。getNumber01中传入的是Lambda表达式,表达式描述的方法包含一个输出语句System.out.println("Lambda");
,目的是检测它是否在作为参数传入时就执行;getNumber02中传入的是一个普通的静态方法,该方法返回一个int值,同时其方法体内也包含一个输出语句System.out.println("getNumber03");
。
由于初始条件的限制,getNumber01和getNumber02在运行的过程中皆不执行if内的return语句,结果如下:
|
|
Lambda表达式没有执行方法内的打印语句,而普通静态类执行了内部的打印语句,此结果验证了Lambda是有条件的延迟执行。
《Java 8实战》一书中举了一个日志查询的例子,用实例分析了Lambda表达式延迟执行的各种好处,比如更易读封装行更好、满足条件才真正执行方法等。用重载构造log方法提供了一个改造旧代码的范例。
环绕执行
环绕执行的具体实现,和前文用重载构造log的实现异曲同工。在书中列举了一个多业务代码“共享”一套准备和清理的例子,这里采用了try-with-resource。
首先当然是函数式接口的创建:
|
|
然后生成一个静态的执行方法:
|
|
接下来就可以通过Lambda表达式实现各种业务逻辑,比如下面的代码中处理了两行:
|
|
以上就是一个环绕执行的简单实现。
小结
本文首先比较了匿名类和Lambda,然后介绍了两种通用的重构模式,有条件延迟执行模式和环绕模式。