小小白祈祷中...

前言

之前有一个小伙伴给我发了一段代码,说是看不懂,这段代码是这样的:

1
2
3
4
5
6
7
8
9
10
public class Aha  {
public static void main(String[] args) {
Care iCare = () -> System.out.println("Hahahahaha~");
iCare.care();
}
}

interface Care{
void care();
}

如果屏幕面前的你也不是很能够理解,那就听我细讲吧。首先,在理解上述代码之前,我们需要了解一个概念-----函数式接口

函数式接口

函数式接口,指只定义了一个抽象方法的接口。

比如如下的接口便是一个最简单的函数式接口:

1
2
3
interface Care{
void care();
}

如果你对jdk的源码有过研究的话,会发现JDK中也提供了许多函数式接口,比如我们熟悉的 Runnable 接口和 Callable 接口:

img

img细心的小伙伴会发现,上面两段源码中均对接口加上了一个注解:@FunctionalInterface ,顾名思义,这表示该接口会被设计成一个函数式接口,不符合规范的话,编译时会报错。

再比如线程池中的 Executor 接口:

img

函数式接口的用处

那么问题来了,将接口设计成函数式接口有什么好处呢?

我们通过一个例子来领会它的妙处,首先,上一段简单的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Haha  {
public static void main(String[] args) {
ILike iLike = new Like();
iLike.like();
}
}

interface ILike{
void like();
}

//普通实现类
class Like implements ILike{
@Override
public void like() {
System.out.println("我是易果啥笔");
}
}

相信学过接口的小伙伴们能够很轻松地看懂上面这段代码。

现在我们深入地想一想,如果ILike这个接口仅仅是在Haha这个类中使用,那我们没必要新建一个外部Like实现类,一个很自然的想法便是将Like实现类设计成静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Haha  {
//静态内部类
static class Like implements ILike{
@Override
public void like() {
System.out.println("我是易果啥笔");
}
}
public static void main(String[] args) {

ILike iLike = new Like();
iLike.like();
}
}
}

interface ILike{
void like();
}

既然想到了设计成静态内部类,为何不干脆设计成局部内部类呢:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Haha  {
public static void main(String[] args) {
ILike iLike = new Like();
iLike.like();
//局部内部类
class Like implements ILike{
@Override
public void like() {
System.out.println("我是易果啥笔");
}
}
}
}

interface ILike{
void like();
}

进一步,如果你学过匿名内部类的话,咱还可以把实现类的类名Like省略,简化成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Haha  {
public static void main(String[] args) {
ILike iLike = new ILike() {
@Override
public void like() {
System.out.println("我是易果啥笔");
}
}; //注意此处要有一个分号结尾

iLike.like();
}
}

interface ILike{
void like();
}

现在,我们来看核心代码:

1
2
3
4
5
6
ILike iLike = new ILike() {
@Override
public void like() {
System.out.println("我是易果啥笔");
}
};

上面这段代码,已经把实现接口的类的类名给省略了,我们想一想,还能不能省略点东西?

Lambda表达式

实际上,iLike前面已有ILike修饰,故后面的“new ILike”字样完全可以省略,不会产生歧义。

而且,重点来了!!!由于ILike本身是一个函数式接口,它只有一个抽象方法 like() ,所以上面的代码中完全可以把重写的like()方法中的“固定代码”去掉而不会产生歧义,甚至花括号也可以去掉,直接写成:

ILike iLike = () System.out.println ( " 我是易果啥笔 " ) ;

当然,在jdk8(或更高)规范中,需要我们加上一个小箭头“ -> ”:

1
ILike iLike = () ->  System.out.println("我是易果啥笔");

到这,我们已经将一个复杂的代码块缩短成了最简单的一行代码,这种用“->”符号来编写的表达式,便称为匿名表达式,也叫Lambda表达式。

从上述过程可以看出,Lambda表达式的优点在于能够使代码变得更为简洁。注意,能够将代码缩短至一行是有一定条件的,下面的代码列举的应该包含绝大多数情况了:

1
2
3
4
5
6
7
8
9
10
11
//如果接口实现的语句不止一个,则必须加上花括号{},这与if,for,while语法类似:
ILike iLike = () -> {
System.out.println("我是易果啥笔");
System.out.println("我是易果啥笔2");
};

//如果接口含且仅含有一个参数(比如含有int a,这时可以省略括号和申明:int)
ILike iLike = a -> System.out.println("我是易果啥笔");

//如果接口含有多个参数(比如含有int a,String b,这时不能省略括号,但仍可以省略申明:int和String)
ILike iLike = (a,b) -> System.out.println("我是易果啥笔");

到这,本文最开始给出的那段代码就很好理解了,其实就是一个简单的Lambda表达式而已:

1
2
3
4
5
6
7
8
9
10
public class Aha  {
public static void main(String[] args) {
Care iCare = () -> System.out.println("Hahahahaha~");
iCare.care();
}
}

interface Care{
void care();
}

事实上,Lambda表达式的应用远不止这些,有兴趣的小伙伴可以去查询更多的资料了解Lambda表达式的其他应用。