java8新特性——Lambda表达式

1.需求分析:

创建一个新的线程,指定线程要执行的任务

package com.wxj.jdk.lambda;

public class Demo01Lambda {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("新线程中执行的代码"+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("主线程中的代码"+Thread.currentThread().getName());
    }
}

代码分析:

1.Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的核心。

2.为了指定这个run方法,不得不需要Runnable的实现类

3.为了省去定义一个Runnable的实现类,不得不使用匿名内部类

4.必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且不能出错,

5.而实际上,我们只在乎方法体中的代码

Lambda表达式就是为了去解决这个问题。

2.Lambda表达式的使用

【1】写法:

Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码:

new Thread(()->{
            System.out.println("lambda线程表达式"+Thread.currentThread().getName());
        }).start();

lambda表达式的优点:简化了匿名内部类的使用,语法更加简单。

匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。

3.Lambda表达式的语法规则

Lambda省去了面向对象的条条框框,Lambda的标准格式由3个部分组成:

(参数类型 参数名称)->{

}

格式说明:

  • (参数类型 参数名称):参数列表
  • {代码体}:方法体
  • ->:箭头,分割参数列表和方法体的

3.1 Lambda练习1

练习无参无返回值的Lambda

定义一个接口:

package com.wxj.jdk.lambda.service;

public interface UserService {
    void show();

}

然后创建主方法使用:

package com.wxj.jdk.lambda;

import com.wxj.jdk.lambda.service.UserService;

public class Demo03Lambda {
    public static void main(String[] args) {
        goShow(new UserService() {
            @Override
            public void show() {
                System.out.println("show方法执行了.....");
            }
        });
        System.out.println("----------------------");
        goShow(()->{
            System.out.println("Lambda show 方法执行了");
        });
    }

    public static void goShow(UserService userService) {
        userService.show();
    }
}

输出:

3.2 Lambda练习2

练习有参有返回值的Lambda表达式案例

创建一个Person对象

package com.wxj.jdk.lambda.domain;

import jdk.jfr.DataAmount;


public class Person {
    private String name;
    private Integer age;
    private Integer height;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }

    public Person(String name, Integer age, Integer height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

然后我们在List集合中保存多个Person对象,然后对这些对象做根据age排序操作

package com.wxj.jdk.lambda;

import com.wxj.jdk.lambda.domain.Person;


import java.util.*;

public class Demo04Lambda {
    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person("周杰伦",33,175));
        list.add(new Person("刘德华",43,175));
        list.add(new Person("周星驰",38,175));
        list.add(new Person("郭富城",23,175));
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        for (Person person : list) {
            System.out.println(person);
        }
        System.out.println("--------------------");
        Collections.sort(list,(Person o1,Person o2)->{
            return o1.getAge() - o2.getAge();
        });
        for (Person person : list) {
            System.out.println(person);
        }
    }
}

然后我们发现在sort方法的第二个参数是一个Comparator接口的匿名内部类,且执行的方法有参数和返回值,那么我们可以改写为Lambda表达式。

输出结果:

4.@FunctionalInterface注解

@FunctionalInterface:这是一个标志注解,被该注解修饰的接口只能声明一个抽象方法

@FunctionalInterface
public interface UserService{
    	void show();
}

5.Lambda表达式的原理

匿名内部类的本质是会在编译时生成一个Class文件。XXXXX$1.class

package com.wxj.jdk.lambda;

public class Demo01Lambda {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("新线程中执行的代码"+Thread.currentThread().getName());
            }
        }).start();
        System.out.println("主线程中的代码"+Thread.currentThread().getName());
        System.out.println("-----------------------------");
        /*new Thread(()->{
            System.out.println("lambda线程表达式"+Thread.currentThread().getName());
        }).start();*/
    }

}

还可以通过反编译工具来查看生成的代码 XJad工具来查看

那么Lambda表达式的原理是什么呢?我们通过JDK自带的一个工具:javap(反编译工具)对字节码进行反汇编操作。

javap -c -p 文件名.class

-c:表示对代码进行反汇编

-p:显示所有的类和成员

在这个反编译的源码中我们看到了一个静态方法lambda$main$0(),这个方法里面做了什么事情呢?

我们可以通过Debug的形式来查看,简单的可以理解成下面的形式:

在这个静态方法中,实现了()->方法体中,方法体的内容。

可以看到这个匿名内部类实现了UserService接口,并重写了show()方法。在show方法中调用了Demo03Lambda.lambda$main$0(),也就是调用了Lambda中的内容。

小结:

匿名内部类在编译的时候会产生一个class文件。

Lambda表达式在程序运行的时候会形成一个类。

1.在类中新增了一个方法,这个方法的方法体就是Lambda表达式中的方法体

2.还会形成一个匿名内部类,实现接口,重写接口中的抽象方法

3.在接口中重写方法会调用新生成的方法

6.Lambda表达式的总结

【1】Lambda表达式的使用前提

Lambda表达式的语法是非常简洁的,但是Lambda表达式不是随便使用的,使用时注意几个条件:

1.方法的参数或局部变量类型必须为接口才能使用Lambda

2.接口中有且仅有一个抽象方法(@FunctionalInterface)

7.Lambda和匿名内部类的对比(面试题)

Lambda和匿名内部类的对比

  • 所需类型不一样

1.匿名内部类的类型可以是类,抽象类,接口

2.Lambda表达式的类型必须是接口

  • 抽象方法的数量不一样

1.匿名内部类所需的接口中的抽象方法的数量是随意的

2.Lambda表达式所需的接口中的抽象方法只能有一个

  • 实现原理不一样

1.匿名内部类是在编译后形成一个class

2.Lambda表达式是在程序运行的时候动态生成class

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值