引入 Lambda 表达式
创建一个线程实现类。
/**
* @author BNTang
*/
public class MyRunnable implements Runnable {
public void run() {
System.out.println("thread -> " + Thread.currentThread().getName() + "启动了");
}
}
实现方法有 3
种如下。
方式 1
通过编写实现类的方式来实现需求,如下。
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
}
}
方式 2
通过匿名内部类的方式来实现,如下。
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("thread -> " + Thread.currentThread().getName() + "启动了");
}
}).start();
}
}
方式 3
通过 Lambda 的方式来实现,如下。
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
new Thread(() -> {
System.out.println("thread -> " + Thread.currentThread().getName() + "启动了");
}).start();
}
}
Lambda 编写格式
(形式参数) -> {代码块}
-
形式参数
:如果有多个参数,参数之间用逗号
隔开;如果没有参数,留空即可。 -
->
:由英文中画线和大于符号组成,固定写法
。代表指向动作。 -
代码块
:是我们具体要做的事情,也就是以前我们写的方法体中的内容。
组成 Lambda 表达式的三要素与使用要求,如下:
- 形式参数
- 箭头
- 代码块
使用要求,如下:
使用 Lambda 表达式必须要有接口,并且要求接口中 有且仅有
一个抽象方法。
下面我将给出一个示例来看看吧,如下:
接口
/**
* @author BNTang
*/
public interface USB {
void work();
}
实现类
/**
* @author BNTang
*/
public class KeyBoardImpl implements USB {
public void work() {
System.out.println("键盘工作");
}
}
应用
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
USB keyBoard = new KeyBoardImpl();
mainBoard(keyBoard);
}
private static void mainBoard(USB usb) {
usb.work();
}
}
如上代码的含义很简单,就是普通的多态的写法,传入一个 USB 的实现类调用 work 方法进行处理。先来看看通过匿名内部类的方式怎么玩吧,如下:
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
mainBoard(new USB() {
public void work() {
System.out.println("鼠标");
}
});
}
private static void mainBoard(USB usb) {
usb.work();
}
}
在来看看通过 Lambda 表达式的方式来怎么玩吧,如下:
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
mainBoard(() -> {
System.out.println("打印机");
});
}
private static void mainBoard(USB usb) {
usb.work();
}
}
带参数形式的 Lambda 表达式。
一个参数
/**
* @author BNTang
*/
public interface TestTable {
void fly(String s);
}
匿名内部类的方式如下:
/**
* @author BNTang
*/
public class FlyableDemo {
public static void main(String[] args) {
useTestTable(new TestTable() {
public void fly(String s) {
System.out.println(s);
}
});
}
private static void useTestTable(TestTable testTable){
testTable.fly("一个参数");
}
}
Lambda 表达式的方式如下:
/**
* @author BNTang
*/
public class FlyableDemo {
public static void main(String[] args) {
useTestTable((String s) -> {
System.out.println(s);
});
}
private static void useTestTable(TestTable testTable) {
testTable.fly("一个参数");
}
}
多个参数
/**
* @author BNTang
*/
public interface Addable {
int add(int x, int y);
}
/**
* @author BNTang
*/
public class AddableMain {
public static void main(String[] args) {
useAddable((int x, int y) -> {
return x + y;
});
}
private static void useAddable(Addable addable) {
int sum = addable.add(10, 20);
System.out.println(sum);
}
}
Lambda 表达式的省略模式
参数的类型可以省略
有多个参数的情况下,不能只省略一个,要么就全部省略不要一个省略一个不省略。
如果参数有且仅有一个,那么小括号可以省略,如下。
如果代码块的语句只有一条,可以省略大括号和分号,如下。
如果代码块的语句只有一条,可以省略大括号和分号,如果有 return
,return
也可以省略掉。
Lambda 表达式的注意事项
使用 Lambda 必须要有接口,并且要求接口中 有且仅有
一个抽象方法。
必须要有上下文环境,才能推导出 Lambda 对应的接口。
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("匿名内部类");
}
}).start();
}
}
可以直接写,因为知道对应的接口是 Runnable
。
/**
* @author BNTang
*/
public class TestMain {
public static void main(String[] args) {
new Runnable() {
public void run() {
System.out.println("匿名内部类");
}
}.run();
}
}
直接这样写会报错,因为没有办法推导出对应的接口。
Lambda 表达式与匿名内部类的区别
所需的类型不同
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类。
Lambda 表达式:只能是接口。
使用的限制不同
如果接口中 有且仅有
一个抽象方法,可以使用 Lambda 表达式,也可以使用匿名内部类。
如果接口中有多于的一个抽象方法,只能使用匿名内部类,而不能使用 Lambda 表达式。
实现的原理不同
匿名内部类:编译之后,会产生一个单独的 .class
字节码文件。
Lambda 表达式:编译之后,没有一个单独的 .class
字节码文件。对应的字节码会在运行的时候动态生成。