Lambda表达式初步与函数式接口
“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
为何需要Lambda表达式
- 在Java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法。
- 在JavaScript中,函数参数一个函数,返回值是另一个函数的情况是非常常见的;JavaScript是一门非常典型的函数式语言。
Java匿名内部类示例:
|
|
这样写是有点繁琐的,在Java8中可以直接下面这样写
|
|
在Java8的循环中,我们也可以很方便的使用Lambda表达式。
示例如下:
|
|
看forEach的方法源码
|
|
接受了一个Consumer参数,这个接口是JDK8新增的一个函数式接口。
什么是函数式接口?
- 一个接口,有且只有一个抽象方法,这个接口就称为函数式接口。
- 如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口。
- 如果某个接口只有抽象方法,但我们并没有给该接口声明@FunctionalInterface注解,那么编译器依旧会将该接口看做是函数式接口。
|
|
我们来试试自己写一个函数式接口。
|
|
Lambda表达式的作用
Lambda表达式为Java添加了缺失的函数式编程特性,使我们能将函数当作一等公民看待。
在将函数作为一等公民的语言中,Lambda表达式是类型是函数。但在Java中,Lambda表达式是对象,他们必须依附于一类特别的对象类型—-函数式接口(functional interface)。
例子
下面是用lambda表达式和stream来对一个列表的字符串进行大写字母转换。
|
|
上面看到有2个冒号的地方,这个叫做方法引用,方法引用有四种方式,这是其中一种,通过类的方式引用。
|
|
这就是一个倒序排序,Collections.sort()的第二个参数就是一个Comparator对象,我们用lambda表示来写的,看一下Comparator是声明为函数式接口。所以可以用lambda来写。
|
|
Java Lambda基本语法
- Java中的Lambda表达式基本语法
- (arg) -> (body)
- 比如
- (arg1, arg2) -> {bodu}
- (type1 arg1, type2 arg2…) -> {body}
示例
- (int a, int b) -> { return a + b; }
- () -> System.out.println(“Hello World”);
- (String s) -> {System.out.println(s);}
- () -> 42
Java Lambda结构
- 一个Lambda表达式可以有零个或多个参数
- 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同。
- 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a,b)或(int a,int b)或(String a,int b, float c)
- 空圆括号代表参数集为空。例如:() -> 42
- 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a * a;
- Lambda表达式的主体可包含零条或多条语句。
- 如果Lambda表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致。
- 如果Lambda表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空。
主要接口详解
Function接口
|
|
compose和andThen
compose()方法,它接受一个Function,也返回一个Function,结果就是执行参数里的apply,再执行本对象的apply。
andThen()方法则相反,是先执行本对象的apply,再执行参数Function的apply。
|
|
BiFunction
接受2个参数,返回一个值的函数式接口。
|
|
Predicate
判断用的函数式接口
|
|
代码测试
Supplier
简单测试
|
|
java.util.function包下面还有很多函数式接口,无非就是0参数,1个参数,2个参数的接口,用法都是一样的。