目录
1. 背景
Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许通过表达式来代替功能接口。lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。Lambda表达式,基于数学中的λ得名,也可称为闭包(Closure)。
1.1 Lambda表达式的语法
基本语法:(parameters) -> expression 或 (parameters) -> {statements;}
Lambda表达式由三部分组成:
1.parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明,也可以不生命而由JVM隐含的进行推断。另外,当只有一个推断类型的时候,可以省略掉圆括号。
2. -> 可以理解为“被用于”的意思
3.方法体:可以是表达式,也可以是代码块,是函数式接口里方法的实现。代码块可返回一个值,或者什么都不返回,这里的代码块等同于方法的方法体。如果是表达式,也可以返回一个值,或者什么都不返回。
1.2 函数式接口
要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法。
注意:
1.如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
2.如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果该接口中有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加上这个注解,加上就会自动进行检测的。
定义方式:
如果多一个抽象方法,注解就会报错
但还有一种情况,是在JDK1.8中的新特性,即default默认方法可以有具体的实现:
2. Lambda表达式的基本使用
我们先可以用前面的一个例子给展现一下Lambda表达式的使用:
在我前面的文章:java数据结构_Map和Set_面试题_9.4-优快云博客中,有一道面试题是求出使用频率前K个单词,其中有一段代码如下:
是建立一个小根堆,但要指定其比较方式,所以自动生成了一段内部类来指定,这一段内部类就可以使用Lambda表达式来代替:
怎么样,是不是初步有了一些认识,接下来我们进行Lambda表达式的基本使用
首先,我们先准备好几个接口:
我们在上面提过,Lambda可以理解为:Lambda就算匿名内部类的简化,实际上是创建了一个类,实现了接口,重写了接口的方法。
如果不使用Lambda表达式的时候的调用方式:
如果使用Lambda表达式:
其他情况下的具体使用如下图:
2.1 语法精简
1.参数类型可以省略,如果需要省略,每个参数的类型都有省略。
2.参数的小括号里面只有一个参数,那么小括号可以省略。
3.如果方法体当中只有一句代码,则大括号可以省略
4.如果方法体中只有一条语句,而且是return语句,那么大括号可以省略,且去掉return关键字。
示例代码:
3. 变量捕获
Lambda表达式中存在变量捕获,了解了变量捕获之后,才能更好的理解Lambda表达式的作用域。Java当中的匿名类,回存在变量捕获。
3.1 匿名内部类
匿名内部类就算没有名字的内部类。我们这里只是为了说明变量捕获,所以,匿名内部类只需简单的只用即可。
示例如下:
上述代码中的main函数当中,就算一个匿名内部类的简单使用。
3.2 匿名内部类的变量捕获
上述代码中,变量a就算捕获的变量。注意:这个变量要么是被final修饰的,如果不是被final修饰的,就一定要保证该变量在被使用之前,没有被修改。
如下代码就算一个错误的代码:此时编译器会直接编译报错!
3.3 Lambda的变量捕获
在Lambda中,也可以进行变量的捕获,代码如下:
注意,此时捕获的变量a同样的不能被修改的
4. Lambda在集合当中的使用
为了能够让Lambda和java的集合类更好的一起使用,集合当中,也新增了部分接口,以便于Lambda表达式对接。
以上方法的作用可自行查看java帮助手册,这里进行一些方法的使用示例。
注意:Collection的forEach方法是从接口java.lang.Iterable拿过来的
4.1 Collection接口
foreach()方法演示:
该方法在接口Iterable当中,原型如下:
该方法表示:对容器中的每个元素执行action指定的动作。
示例如下:
结果如下:
也可以修改为如下代码,使用lambda表达式:
可见,结果是相同的。
4.2 List接口
sort()方法的演示:
sort方法源码:该方法根据c语言指定的比较规则对容器元素进行排序。
使用示例:
进行lambda表达式的修改:
方法体中只有一句代码,可以不用加花括弧。
4.3 Map接口
HashMap的forEach()
源码如下:
作用是对Map重点每个映射执行action指定的操作。
代码示例:
改写为lambda表达式:
5. 总结
Lambda表达式的优点很明显,在代码层次上来说,使得代码变的非常整洁。缺点也很明显,代码易读性差。
优点:
1.代码简洁,开发迅速
2.方便函数式编程
3.非常容易进行并行计算
缺点:
1.代码可读性变差
2.在非并行计算中,很多计算未必有传统的for性能高
3..不容易进行调试