首先我们看一下什么是lambda表达式。以下是维基百科上对于”Lambda expression”的解释:
a function (or a subroutine) defined, and possibly called, without being bound to an identifier。
简单点说就是:一个不用被绑定到一个标识符上,并且可能被调用的函数。这个解释还不够通俗,lambda表达式可以这样定义(不精确,自己的理解):一段带有输入参数的可执行语句块。
函数式接口
函数式接口(functional interface 也叫功能性接口,其实是同一个东西)。简单来说,函数式接口是只包含一个方法的接口。比如Java标准库中的java.lang.Runnable和java.util.Comparator都是典型的函数式接口。java 8提供@FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口),虚拟机会自动判断,但 最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。 Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口的实现。
Lambda语法详解
包含三个部分: 1、一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数 2、一个箭头符号:-> 3、方法体,可以是表达式和代码块,方法体函数式接口里面方法的实现,如果是代码块,则必须用{}来包裹起来,且需要一个return 返回值,但有个例外,若函数式接口里面方法返回值是void,则无需{}
我们在此抽象一下lambda表达式的一般语法:
1
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
从lambda表达式的一般语法可以看出来,还是挺符合上面给出的非精确版本的定义–“一段带有输入参数的可执行语句块”。上面的lambda表达式语法可以认为是最全的版本,写起来还是稍稍有些繁琐。别着急,下面陆续介绍一下lambda表达式的各种简化版:
1. 参数类型省略–绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型。这样lambda表达式就变成了:
1
(param1,param2, ..., paramN) -> {
所以我们最开始的例子就变成了(省略了List的创建):
1
List<String> lowercaseNames = names.stream().map((name) -> {
return
name.toLowerCase();}).collect(Collectors.toList());
2. 当lambda表达式的参数个数只有一个,可以省略小括号。lambda表达式简写为:
所以最开始的例子再次简化为:
1
List<String> lowercaseNames = names.stream().map(name -> {
return
name.toLowerCase();}).collect(Collectors.toList());
3. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。lambda表达式简化为:
所以最开始的例子再次简化为:
1
List<String> lowercaseNames = names.stream().map(name -> name.toLowerCase()).collect(Collectors.toList());
方法引用
其实是lambda表达式的一个简化写法,所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是
类名,实例名),中间是"::",右边是相应的方法名。
一般方法的引用格式是: 1、如果是静态方法,则是ClassName::methodName。如 Object::equals 2、如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;
构造器引用
构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。例如BigDecimal::new等同于x->new BigDecimal(x)。