@[toc]
前言
java 8 一个大亮点就是引入了 lambda 表达式,使得代码开发更加简单。主要用于定义行内执行的方法类型接口,比如有一个接口你懒得去实现然后调用其方法就可以写一个 lambda 表达式
lambda 表达式到底做了什么事呢?具体的理解就是它实际上是一个接口的匿名实现类,箭头后是对接口中的抽象方法进行了实现,箭头前是抽象方法的传参
函数式接口
我们在学习 java 8 的 lambda 表达式的时候,首先必须要知道的就是函数式接口,这个词和 java 8 lambda 表达式一起出现的,二者相辅相成,lambda 表达式是函数式接口的匿名实现
函数式接口,是一种特殊的接口,与 java 8 中 lambda 表达式同时被定义,jdk 中使用 @FunctionalInterface
标在接口上方,来指明此接口是函数式接口,作为函数是接口表示其可以接收 lambda 表达式作为该类接口的匿名实现,比如Map.forEach()
方法中接收的是一个 BiConsumer 函数式接口,因此其中可以写 lambda 表达式表示匿名实现这个函数式接口
一般的接口中所有方法必须都是抽象方法,对于函数式接口中不仅可以定义静态方法,还可以定义 default 修饰的方法default void
这样该函数是接口就可以直接 new 并且调用此方法
基本格式
->
前为参数,后为函数表达式的返回
expression 是一般的表达式,比如可以是a+b
,不加括号表示实现的方法返回是a+b
statements 表达式可以是a=1
但是如果写a+b
会报错,加了括号表示返回的是整个括号中内容
(parameters) -> expression
(parameters) -> {statements;}
复制代码
简单示例
public class JustForTest {
@Test
public void test() {
A addition = (a, b) -> a + b;
System.out.println(addition.caozuo(1, 2));
}
interface A {
int sum(int x, int y);
}
}
复制代码
这个示例简单明了,addition 就类似于一个接口实现类然后使用A addiction = new 接口匿名的实现类()
一样的效果了。这种 lambda 表达式的运用可以帮助我们少些很多代码
作用域
我们下面直接看几个小例子
样例一
在 lambda 表达式中声明的变量不可以在表达式外部使用。其实也很好理解,因为表达式中实际等价于实现了一个匿名内部类,类中方法中的变量是不可以在外部使用的
样例二
作为类的 field 变量,在方法中的 lambda 表达式里可以引用它,并且可以做修改。直接看下面的例子中 variable 吧
样例三
作为方法中的变量,方法中的 lambda 表达式中不可以修改此变量,在运行之前就可以检测出错误。下方红色波浪线。也就是说这时候其隐含了 final 属性
Map.forEach()
前文也提到了,forEach()
方法中接收一个函数式接口 BiConsumer,因此这里可以使用 lambda 表达式(该函数式接口的匿名实现)
Map<String, String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.forEach((key, value) -> {
System.out.println(key + ":" + value);
});
复制代码
Stream中的 lambda
java 8 的流式处理也是一个很好新特性,它常常会伴随着 lambda 表达式一起使用,集合类调用流的stream() 方法,然后再调用 Stream 接口中的方法,这些方法中的参数很多都是接口,这样就可以做成 lambda 表达式了。
这里没有专门讲 Stream 流式处理,博主的另一篇博文:java8新特性-stream流式处理 专门有讲解
双冒号 :: 简写 lambda
双冒号::
是用来简写 lambda 表达式,让其更加简洁,这种简写学名是η-conversion
,读作eta-conversion
。双冒号前面的为类名,后面是该类中的方法,整体表示匿名实现某个接口,接口中方法的实现使用的是该类中的方法
具体怎么理解呢?双冒号的整个表达式实际就是一个接口的匿名实现类,双冒号后是用什么已经实现的方法代替要实现的接口中的抽象方法,双冒号前指明是哪个类
举个例子,现在假如存在接口 A,我们来写个常规的 lambda 表达式
interface A {
int sum(int a, int b);
}
public class JustForTest {
@Test
public void test1() {
A a = (a, b) -> a + b;
}
}
复制代码
我们再用双冒号来实现
interface A {
int sum(int a, int b);
}
public class JustForTest {
@Test
public void test1() {
A a = Integer :: sum;
}
}
复制代码