lambda表达式,也成为闭包,java8最重要的新特性。lambda表达式允许把函数作为一个方法的参数传递进方法中 。目的是为了使代码更简洁紧凑。应该说lambda表达式具有动态实现接口的功能,且是一次性的。没有污染随意定制,避免了匿名方法的麻烦,且给与java简单强大的函数化的编程能力。
函数式编程?
- 将业务逻辑细化,抽象,封装成一个个功能函数,并借助语言自带的高阶函数api,将整个业务流程转化为函数之间的相互调用,这就是函数式编程。
我们可以看到,函数式编程中,函数不仅直接调用,也可以当成参数被其他函数调用。
因此,进一步,如果我不仅想把函数当参数,还想传入值,所以再封装一下,函数和值封装后是什么。
- 函数->行为
- 值->属性
没错就是这就是对象
- 将业务逻辑细化,抽象,封装成一个个对象,并借助语言,库,组件,框架等,将整个业务流程转化为对象之间的相互调用,这就是面向对象编程。
因此,这么看来,函数式跟面向对象的思想其实都是一致的,即对逻辑的抽象与封装。
回顾下语言的历程
过程式->函数式->面向对象
近年来大数据的兴起,数据的处理往往跟面向对象没关系,更多的是简单而大量的数据结构,借助mapreduce这样的高阶函数处理更加方便,这也是函数式编程又火起来的原因。
程序只不过是回到了它的原点:
算法+数据结构->函数+高阶函数+数据。
Lambda表达式语法格式:
(parameters) -> expression 或 (parameters) ->{ statements; }
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
所以总结下来就是:
1. 没有参数类型这个说法。
2. 参数个数为1无需圆括号,但大于1需要定义圆括号。
3. 主题超过一个句子就要使用大括号。
4. 如果主题只有一个表达式或者值,编译器会自动把值返回,除非不需要指定返回值,否则需要指定返回值。
5. 圆括号:参数;大括号:主题(函数);
attention :
lambda 表达式只能引用标记了 final 的外层局部变量,否则会编译报错。可以不声明为final,但是后续不可以修改该属性。
lambda不允许声明局部变量和圆括号内的参数名相同。
java.util.function.Function的用法:
jdk1.8 api中包含了很多建的函数式接口,同时在老的java中如comparator和runnable接口也都添加了@FunctionalInterface注解以便能用在lambda上。
标注为FunctionalInterface的接口被称为函数式接口,该接口只能由一个未实现的方法,同时一个接口如果只有一个方法,则编译器会认为这是一个函数式接口,是否是一个函数式接口,需要注意以下几点:
1. 该注解只能标记在”有且仅有一个抽象方法”的接口上。
2. JDK8接口中的静态方法和默认方法,都不算是抽象方法。
3. 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
在一个接口中定义两个自定义的方法,就会产生Invalid ‘@FunctionalInterface’ annotation; FunctionalInterfaceTest is not a functional interface错误。
如Function接口:
接受对象a,返回对象b。
该lambda表达式中的参数Function<PredicateSpec, AsyncBuilder> fn 是一个函数式接口,且a对象只能为PredicateSpec,ok开始使用lmabda表达式构建该函数接口,
PredicateSpec对象有个方法:
BooleanSpec对象有个方法filters
UriSpec对象有个方法uri,最后得到了AsyncBuilder对象,而AsyncBuilder对象就是Function<PredicateSpec, AsyncBuilder>这个函数的要实现的目的。
上图中的蓝色部分就是实现函数接口Function的apply方法,最后蓝色部分成为了一个函数,然后将函数以对象的形式传入参数中,这也是lmbda表达式中的一项功能,函数能以参数的形式传入方法中。