Lambda 体验
Lambda 是一个匿名函数, 可以理解为一段可以传递的代码.
Lambda 表达式写法, 代码如下:
借助 Java 8 的全新语法, 上述 Runnable 接口的匿名内部类写法可以通过更简单的 Lambda 表达式达到相同的效果
- /**
- * 从匿名类到 Lambda 表达式的转变
- */
- @Test public void testLambdaHelloWorld() {
- // 匿名类 01
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("Hello");
- }
- }).start();
- // lambda01
- new Thread(() -> System.out.println("Hello")).start();
- }
这段代码和刚才的执行效果是完全一样的, 可以在 JDK 8 或更高的编译级别下通过. 从代码的语义中可以看出: 我们启动了一个线程, 而线程任务的内容以一种更加简洁的形式被指定. 我们只需要将要执行的代码放到一个 Lambda 表达式中, 不需要定义类, 不需要创建对象. Lambda 的优点: 简化匿名内部类的使用, 语法更加简单.
Lambda 的标准格式
Lambda 省去面向对象的条条框框, Lambda 的标准格式格式由 3 个部分组成:
(参数类型 参数名称) -> {
代码体;
}
无参数无返回值的 Lambda
- @Test
- public void test(){
- goSwimming(new Swimmable(){
- @Override
- public void swimming() {
- System.out.println("我要游泳");
- }
- });
- goSwimming( () -> {
- System.out.println("我要游泳");
- });
- }
- // 练习无参数无返回值的 Lambda
- public static void goSwimming(Swimmable s) {
- s.swimming();
- }
- /**
- * @author WGR
- * @create 2020/3/23 -- 23:29
- */
- public interface Swimmable {
- public abstract void swimming();
- }
有参数有返回值的 Lambda
- @Test
- public void test1(){
- goEatting( name ->{
- System.out.println("吃"+name);
- return 0 ;
- });
- }
- public static Integer goEatting(Eatable e){
- return e.eatting("饭");
- }
- /**
- * @author WGR
- * @create 2020/3/23 -- 23:29
- */
- public interface Swimmable {
- public abstract void swimming();
- }
- @Test
- public void test3(){
- ArrayList<Person> persons = new ArrayList<>();
- persons.add(new Person("刘德华", 58, 174));
- persons.add(new Person("张学友", 58, 176));
- persons.add(new Person("刘德华", 54, 171));
- persons.add(new Person("黎明", 53, 178));
- Collections.sort(persons, (o1, o2) -> {
- return o2.getAge() - o1.getAge(); // 降序
- });
- persons.forEach((t) -> {
- System.out.println(t);
Lambda 的实现原理
匿名内部类的 class 文件
Lambda 表达式的断点
关于这个方法 lambda$test$1 的命名: 以 lambda 开头, 因为是在 test()函数里使用了 lambda 表达式, 所以带有 $test 表示, 因为是第二个, 所以 $01 如何调用这个方法呢? 其实 Lambda 在运行的时候会生成一个内部类, 为了验证是否生成内部类, 可以在运行时加
上 -Djdk.internal.lambda.dumpProxyClasses , 加上这个参数后, 运行时会将生成的内部类 class 码输出到一个文
件中. 使用 java 命令如下:
java -Djdk.internal.lambda.dumpProxyClasses 要运行的包名. 类名
小结 :
匿名内部类在编译的时候会一个 class 文件
Lambda 在程序运行的时候形成一个类
1. 在类中新增一个方法, 这个方法的方法体就是 Lambda 表达式中的代码
2. 还会形成一个匿名内部类, 实现接口, 重写抽象方法
3. 在接口的重写方法中会调用新生成的方法.
Lambda 省略格式
- /**
- * lambda 语法: 能省则省
- */
- @SuppressWarnings("unused")
- @Test public void testLambdaSyntax() {
- // 语法
- BinaryOperator<Integer> bo = (Integer x, Integer y) -> {
- return x+y;
- };
- // 简化 1: 由于类型推断(编译器 javac 根据上下文环境推断出类型), 可以省略参数的类型
- bo = (x,y) -> {
- return x+y;
- };
- // 简化 2: 当 Lambda 体只有一条语句的时候可以省略 return 和大括号{}
- bo = (x,y) -> x + y;
- // 简化 3: 当参数只有一个时, 可以省略小括号
- Consumer<String> fun = args -> System.out.println(args);
- // 简化 4: 当参数个数为零时, 使用 () 即可
- Runnable r1 = () -> System.out.println("Hello Lambda");
- // 简化 5: 方法引用(下个新特性)
- Consumer<String> fun02 = System.out::println;
- }
Lambda 的前提条件 Lambda 的语法非常简洁, 但是 Lambda 表达式不是随便使用的, 使用时有几个条件要特别注意:
1. 方法的参数或局部变量类型必须为接口才能使用 Lambda
2. 接口中有且仅有一个抽象方法
- /**
- * @author WGR
- * @create 2020/3/24 -- 0:11
- */
- public class LambdaCondition {
- public static void main(String[] args) {
- // 方法的参数或局部变量类型必须为接口才能使用 Lambda
- test(() -> {
- });
- Flyable f = () -> {
- System.out.println("我会飞啦");
- };
- }
- public static void test(Flyable a) {
- new Person() {
- };
- }
- }
- // 只有一个抽象方法的接口称为函数式接口, 我们就能使用 Lambda
- @FunctionalInterface // 检测这个接口是不是只有一个抽象方法
- interface Flyable {
- // 接口中有且仅有一个抽象方法
- public abstract void eat();
- // public abstract void eat2();
- }
来源: http://www.bubuko.com/infodetail-3475505.html