public class LambdaDemo {
public static void main(String[] args) {
//开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程执行代码");
}
}).start();
}
}
分析:
当我们以 new Thread().start() 的方式启动一个线程时,我们做了如下3件事情:
- 定义了一个没有名字的类(匿名类)
- 这个类的参数参数,调用的是 Runnable 接口
- 我们通过 new Runnable(){...}的方式创建了这个类,并重写了该接口的 run() 方法
在这个示例中,其实我们关注的并不是 new Runnable() 这个过程,而是如下2点:
- run() 方法 (参数情况)
- {...}方法体中执行的代码
在以上Demo中,针对使用匿名内部类语法冗余的问题,JDK8推出了 Lambda 表达式。
- Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中即可(函数就是类中的方法);
- Lambda表达式就是一个匿名函数,我们只需要将执行的代码放到 Lambda 表达式中即可。
Lambda省去面向对象的条条框框,Lambda的标准格式由3部分组成:
(参数类型 参数名称) -> {
方法体;
return 返回值;
}
格式说明:
- (参数类型 参数名称):参数列表部分
- {...}:方法体,即要执行的代码部分
- ->:箭头,无实际含义,起到连接参数列表和方法体的左永刚
- 小括号中的参数类型可以省略。
- 如果小括号中只有一个参数,那么可以省略小括号。
- 如果大括号中只有一条语句,那么可以同时省略大括号、return关键字及语句分号。
public class LambdaDemo {
public static void main(String[] args) {
//匿名内部类方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程执行代码了");
}
}).start();
//体验Lambda表达式
new Thread(() ->{
System.out.println("Lambda表达式执行了");
}).start();
}
}
☆ 可以简化匿名内部类,让代码更加精简
☆ Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。
1.无参数无返回值的Lambda表达式
①定义一个接口类ISwim,接口中定义一个抽象方法 swimming();
/**
* ISwim接口
*/
public interface ISwim {
//swimming()抽象方法
public abstract void swimming();
}
②定义一个方法 goSwimming(ISwim swim),注意该方法参数是一个接口类ISwim。然后 main 中调用该方法;
public class LambdaDemo {
public static void main(String[] args) {
//1.使用匿名内部类方式
goSwimming(new ISwim() {
@Override
public void swimming() {
System.out.println("我是匿名内部类的游泳");
}
});
//2.Lambda表达式方式
goSwimming(()->{
System.out.println("我是Lambda表达式的游泳");
});
}
//goSwimming(ISwim swim) 方法
public static void goSwimming(ISwim swim){
swim.swimming();
}
}
//测试结果:
// 我是匿名内部类的游泳
// 我是Lambda表达式的游泳
2.有参数有返回值的Lambda表达式
①定义一个接口类ISmoke,接口中定义一个具有返回值(int)的抽象方法 smoking();
/**
* ISmoke接口
*/
public interface ISmoke {
//smoking()抽象方法
public abstract int smoking(String name);
}
②定义一个方法 goSwimming(ISwim swim),注意该方法参数是一个接口类ISwim。然后 main 中调用该方法;
public class LambdaDemo {
public static void main(String[] args) {
//1.使用匿名内部类方式
goSmoking(new ISmoke() {
@Override
public int smoking(String name) {
System.out.println("匿名内部类:抽了"+ name + "牌香烟");
return 5;
}
});
//2.使用Lambda表达式方式
goSmoking((String name)->{
System.out.println("Lambda表达式:抽了"+ name + "牌香烟");
return 6;
});
}
//有参数有返回值的Lambda
public static void goSmoking(ISmoke smoke){
int i = smoke.smoking("中华");
System.out.println("返回值:"+i);
}
}
//测试结果:
// 匿名内部类:抽了中华牌香烟
// 返回值:5
// Lambda表达式:抽了中华牌香烟
// 返回值:6
我们有一个List集合,集合中存放了 4个Person对象,Person对象中有 name,age,height 属性。对集合进行排序,我们会使用到 Collections 工具类中的 Collections.sort()方法。
sort()方法中传递的两个参数:1.list集合 2.Comparator 比较器。我们发现 Comparator 是一个接口,所以此处也可以使用 Lambda 表达式来替代匿名内部类。
/**
* Person实体类
*/
public class Person {
private String name;
private int age;
private int height;
public Person(String name, int age, int height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
public class CollectionsLambdaDemo{
public static void main(String[] args) {
List persons = new ArrayList<>();
persons.add(new Person("刘德华",58,174));
persons.add(new Person("张学友",56,176));
persons.add(new Person("郭富城",54,171));
persons.add(new Person("黎明",53,178));
//1.匿名内部类,对集合进行排序
Collections.sort(persons, new Comparator() {
//年龄降序排序
@Override
public int compare(Person o1, Person o2) {
return o2.getAge() - o1.getAge();
}
});
for (Person person: persons) {
System.out.println(person);
}
System.out.println("-----------------------------------");
//2.Lambda表达式
Collections.sort(persons,(Person o1,Person o2) ->{
return o1.getAge() - o2.getAge();
});
for (Person person: persons) {
System.out.println(person);
}
}
}
//测试结果:
Person{name='刘德华', age=58, height=174}
Person{name='张学友', age=56, height=176}
Person{name='郭富城', age=54, height=171}
Person{name='黎明', age=53, height=178}
-----------------------------------
Person{name='黎明', age=53, height=178}
Person{name='郭富城', age=54, height=171}
Person{name='张学友', age=56, height=176}
Person{name='刘德华', age=58, height=174}
1.方法的参数或局部变量类型必须为接口,才能使用Lambda
eg:局部变量类型:(Runnable是一个接口)
匿名内部类方式:
Runnable r = new Runnable(){
@override
public void run(){
System.out.println("xxx");
}
}
这种情况,你要来个局部变量,可以使用 Lambda表达式
Runnable r = ()-> System.out.println("xxx");2.接口中有且仅有一个抽象方法
JDK8中,只有一个抽象方法的接口称为函数式接口,我们就能使用 Lambda。
针对一个接口中,有两个抽象方法:JDK8为我们新增了一个注解:@FunctionalInterface。它能够帮助我们检测这个接口是不是只有一个抽象方法,如果有两个抽象方法,则会报错。
请跳转学习:Lambda表达式原理分析
1.所需的类型不一样
匿名内部类,需要的类型可以使类,抽象类,接口;
Lambda表达式,需要的类型必须是接口。
2.抽象方法的数量不一样
匿名内部类所需的接口中抽象方法的数量随意;
Lambda表达式所需的接口只能有一个抽象方法。
3.实现原理不同
匿名内部类是在编译后,会形成额外的一个 类名$0 的.class文件
Lambda 表达式实在程序运行的时候动态生成 .class 文件
当接口中只有一个抽象方法时,建议使用 Lambda 表达式;其他情况下,还是需要使用匿名内部类。
本目录为 JDK8新特性 学习目录,包含JDK8 新增全部特性的介绍。
如需了解,请跳转链接查看:我是跳转链接
博主写作不易,来个关注呗
求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙
博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ