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