Lambda表达式
-
概述
Lambda表达式可以看做一个可以重写函数式接口抽象方法的实现类对象。 -
使用前提
- .必须是接口,并且接口中有且仅有一个抽象方法。(函数式接口)
- .有上下文环境,才能推导出Lambda对应的接口"实现类对象"。
- 根据局部变量的赋值推导Lambda对应的接口:Runnable r = () -> System.out.println(“Lambda表达式”);
- 根据调用方法的参数推导Lambda对应的接口:new Thread(() -> System.out.println(“Lambda表达式”)).start();
-
Lambda的标准格式
- 格式:(形式参数) -> {代码块}
- 形式参数:根据函数式接口抽象方法的参数而定,有多个参数用逗号隔开;没有参数就留空
- ->:固定写法,代表指向动作。
- 代码块:具体要做的事情,类似匿名内部类方法体内容。(抽象方法的方法体具体实现)
- 格式:(形式参数) -> {代码块}
-
启动一个线程,用实现Runnable接口、匿名内部类和Lambda表达式进行对比
class MyRunnable implements Runnable{ @Override public void run() { System.out.println("Runnable线程启动了"); } } public class Demo { public static void main(String[] args) { //实现Runnable接口,启动新线程 MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr); t1.start(); //匿名内部类,启动新线程 new Thread(new Runnable() { @Override public void run() { System.out.println("匿名内部类线程启动了"); } }).start(); //Lambda表达式,启动新线程 new Thread(() -> { System.out.println("Lambda线程启动了"); }).start(); } } ---*--- 输出结果: Runnable线程启动了 匿名内部类线程启动了 Lambda线程启动了
Lambda表达式 ( ) -> { },和匿名内部类对比可以将:
- ( ):看作抽象方法形式参数为空
- ->:箭头指向方法体
- { }:看作方法体中的内容
练习
-
函数式接口,无参无返回值抽象方法
//有且仅有一个抽象方法的接口 interface A{ void eat(); }
class B implements A{ @Override public void stude() { System.out.println("好好学习,天天向上"); } } public class Demo { public static void main(String[] args) { //创建实现类 B b = new B(); show(b); //匿名内部类 show(new A() { @Override public void stude() { System.out.println("好好学习,天天向上"); } }); //Lambda show(()->{ System.out.println("好好学习,天天向上"); }); } //参数是A接口的测试方法 public static void show(A a){ a.eat(); } } ---*--- 输出结果: 好好学习,天天向上 好好学习,天天向上 好好学习,天天向上
-
函数式接口,带参无返回值抽象方法
//接口,一个带参抽象方法 interface A{ void stude(String s); }
public class Demo { public static void main(String[] args) { //匿名内部类 show(new A() { @Override public void stude(String s) { System.out.println(s); System.out.println("好好学习,天天向上"); } }); //Lambda show((String s)->{ System.out.println(s); System.out.println("好好学习,天天向上"); }); } //调用接口的测试方法 public static void show(A a){ a.stude("圆圆"); } } ---*--- 输出结果: 圆圆 好好学习,天天向上 圆圆 好好学习,天天向上
-
函数式接口,带参有返回值抽象方法
//函数接口,带参有返回值 interface A{ int add(int x, int y); }
public class Demo { public static void main(String[] args) { //Lambda test((int x, int y) ->{ return x+y; }); } //调用接口的测试方法 public static void test(A a){ int add = a.add(10, 20); System.out.println(add); } } ---*--- 输出结果: 30
Lambda省略模式
-
概述:
- 1.参数类型可以省略。如有多个参数只能都省略或都不省略。
- 2.参数有且仅有一个,圆括号可以省略。
- 3.如果代码块语句只有一条,可以省略大括号和分号;有返回值还要省略return。
-
①省略参数类型
//函数式接口 public interface Inter { int est(int x, int y); }
public class Demo { public static void main(String[] args) { //Lambda show((int x,int y) -> { return x+y; }); //ambda省略参数类型 show((x,y) -> { return x+y; }); } public static void show(Inter in){ int est = in.est(10, 20); System.out.println(est); } } ---*--- 输出结果: 30 30
注意:有多个参数的情况下,只能都省略或者都不省略。
-
②如果只有一个参数,小括号可以省略。
//函数式接口 public interface Inter { void est(int x); }
public class Demo { public static void main(String[] args) { //Lambda show((x) ->{ System.out.println(x); }); //Lambda,省略圆括号 show(x -> { System.out.println(x); }); } public static void show(Inter in){ in.est(100); } } ---*--- 输出结果: 100 100
-
③如果代码块的语句只有一条,可以省略花括号和分号
//函数式接口 public interface Inter { void est(int x); }
public class Demo { public static void main(String[] args) { //Lambda show(x ->{ System.out.println(x); }); //Lambda,省略大括号 show(x -> System.out.println(x)); } public static void show(Inter in){ in.est(100); } } ---*--- 输出结果: 100 100
注意:Lambda表达式在只有一条语句,省略调花括号和分号的情况下。如果该抽象方法有返回值,还需要省略 return。
Lambda表达式和匿名内部类的区别
-
所需类型不同
-
匿名内部类:可以是接口、抽象类和具体类
-
Lambda表达式:只能是接口
//函数式接口 public interface S1 { void inter(); } //抽象类 abstract class S2{ abstract void abs(); } //具体类 class S3{ void cla(){} }
public class Demo { //测试方法,参数为接口,抽象类和具体类对象 public static void show1(S1 s1){ s1.inter(); } public static void show2(S2 s2){ s2.abs(); } public static void show3(S3 S3){ S3.cla(); } //mian方法 public static void main(String[] args) { //传入匿名内部类对象 show1(new S1() { @Override public void inter() { System.out.println("inner-s1"); } }); show2(new S2() { @Override void abs() { System.out.println("inner-s2"); } }); show3(new S3(){ @Override void cla() { System.out.println("inner-s3"); } }); //传入Lambda表达式推导的实现类对象 show1(() -> { System.out.println("Lambda-s1"); }); // show2(() -> {});//报错,Lambda转换的目标类型必须是接口 // show3(() -> {});//报错,Lambda转换的目标类型必须是接口 } } ---*--- 输出结果: inner-s1 inner-s2 inner-s3 Lambda-s1
-
-
使用限制不同
- 接口中有且仅有一个抽象方法,可以使用Lambda表达式或匿名内部类
- 接口中有多个抽象方法,只能使用匿名内部类。
//有多个抽象方法的接口 public interface S1 { void inter(); void inter1(); }
public class Demo { //测试方法,参数为接口 public static void show1(S1 s1){ s1.inter(); } //main public static void main(String[] args) { //匿名内部类 show1(new S1() { @Override public void inter() { System.out.println("inner-s1"); } @Override public void inter1() { } }); //Lambda // show1(() -> {});//报错,存在多个抽象方法 } }
-
实现原理不同
- 匿名内部类:编译后,产生一个单独的.class字节码文件
- Lambda表达式:编译后,不产生单独的.class字节码文件。对应的字节码会在运行时动态生成。