一、Lambda表达式是什么
简单来说,Lambda表达式是一个可传递的代码段。可以不借助对象传递的一个代码段。那java作为一个面向对象的语言,为什么要加入这么一个特性呢?
二、为什么使用Lambda表达式
从一个简单的例子开始。
比如现在有一个Person类
package POJO;
import lombok.Data;
import java.util.Objects;
/**
* @author wangtianqi
* @create 2020-08-19 15:59
*/
@Data
public class Person {
private String name;
private Integer age;
private String country;
private char sex;
}
如果不使用Lambda表达式将下面这个Person集合中的元素按照年龄从小到大排序。
List<Person> personList = new ArrayList<>();
//personList.add(new Person("欧阳霜",18,"中国",'F'));
personList.add(new Person("欧阳雪", 18, "中国", 'F'));
personList.add(new Person("Tom", 24, "美国", 'M'));
personList.add(new Person("Harley", 22, "英国", 'F'));
personList.add(new Person("向天笑", 23, "中国", 'M'));
personList.add(new Person("李康", 22, "中国", 'M'));
personList.add(new Person("小梅", 20, "中国", 'F'));
personList.add(new Person("何雪", 21, "中国", 'F'));
personList.add(new Person("李康", 22, "中国", 'M'));
很自然的可以想到,使用工具类Collections中的sort方法。sort方法需要提供一个Comparator接口的实现类。
package POJO;
import java.util.Comparator;
/**
* @author wangtianqi
* @create 2020-09-08 10:03
*/
public class ComparePerson implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}
然后使用sort方法将集合排序。
/**
* lambda表达式相关
*
* @author wangtianqi
* @create 2020-09-08 10:05
*/
public class Test3 {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
//personList.add(new Person("欧阳霜",18,"中国",'F'));
personList.add(new Person("欧阳雪", 18, "中国", 'F'));
personList.add(new Person("Tom", 24, "美国", 'M'));
personList.add(new Person("Harley", 22, "英国", 'F'));
personList.add(new Person("向天笑", 23, "中国", 'M'));
personList.add(new Person("李康", 22, "中国", 'M'));
personList.add(new Person("小梅", 20, "中国", 'F'));
personList.add(new Person("何雪", 21, "中国", 'F'));
personList.add(new Person("李康", 22, "中国", 'M'));
Collections.sort(personList,new ComparePerson());
// 遍历打印
for (Person person : personList) {
System.out.println(person);
}
}
}
例子到这就结束了。再回过头看main方法中的Collections.sort(personList,new ComparePerson());
这条语句。如果仅仅是看这条语句,并不能直观的了解到这个排序是按照哪个条件进行的。需要找到ComparePerson这个实现类,才能看到排序的条件。代码的可读性不高。并且提供实现类,也需要编写代码,代码不简洁。
如果java支持函数式编程,就可以很好的解决这问题。例如ComparePerson类中只提供了一种方法。使用函数式编程,就不需要为了这个代码段编写一个类,直接在需要的地方编写一个代码段即可。
lambda表达式就是为了让java实现函数式编程而出现的。
三、Lambda表达式的语法
接着上面一节,这次我们使用Lambda表达式实现集合排序。
import POJO.ComparePerson;
import POJO.Person;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* lambda表达式相关
*
* @author wangtianqi
* @create 2020-09-08 10:05
*/
public class Test3 {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
//personList.add(new Person("欧阳霜",18,"中国",'F'));
personList.add(new Person("欧阳雪", 18, "中国", 'F'));
personList.add(new Person("Tom", 24, "美国", 'M'));
personList.add(new Person("Harley", 22, "英国", 'F'));
personList.add(new Person("向天笑", 23, "中国", 'M'));
personList.add(new Person("李康", 22, "中国", 'M'));
personList.add(new Person("小梅", 20, "中国", 'F'));
personList.add(new Person("何雪", 21, "中国", 'F'));
personList.add(new Person("李康", 22, "中国", 'M'));
// Collections.sort(personList,new ComparePerson());
Collections.sort(personList, (p1, p2) -> p1.getAge() - p2.getAge());
for (Person person : personList) {
System.out.println(person);
}
}
}
我们使用非常简短的一个代码段完成了ComparePerson类提供的功能。代码更简洁。并且对比使用实现类的语句,这段代码可以很清楚的了解到这次排序是按照年龄进行的。可读性更好。
lambda表达式基本语法
- Java8中引入了一个新的操作符,
->
,该操作符称为箭头操作符或者Lambda操作符,箭头操作符将Lambda表达式拆分成两部分; - 左侧: Lambda表达式的参数列表,对应的是接口中抽象方法的参数列表;
- 右侧: Lambda表达式中所需要执行的功能(Lambda体),对应的是对抽象方法的实现;(函数式接口(只能有一个抽象方法))
- Lambda表达式的实质是 对接口的实现;当接口只有一个方法(非静态方法,非默认方法)时,才可以使用lambda表达式。
四、函数式接口
上面提到了当接口只有一个方法(非静态方法,非默认方法)时,才可以使用lambda表达式。 在java中这种接口叫做,函数式接口。可以使用@FunctionalInterface
注解来声明某个接口是一个函数式接口。
当在方法中的某个参数为函数式接口的引用时,在调用该方法时,就可以使用lambda表达式为该接口引用提供一个具体实现。
看一眼sort方法的源码,第二个参数Comparator<? super T> c
是一个接口引用。
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
点进去看一眼,果然Comparator<T>
是一个函数式接口。所以我们可以在使用sort方法时使用lambda表达式作为第二个参数。
@FunctionalInterface
public interface Comparator<T> {
五、Java中提供的四大函数式接口
如果你想要在自己的方法中添加函数式接口引用作为参数,Java提供了非常有代表性的四个函数式接口,我们只需要选择自己想要的接口即可。
四大函数式接口
Consumer< T >
消费型 接口:void accept(T t);
- 消费型接口Consumer,是一个有参数,但是无返回值类型的接口(void accept(T t);)
Supplier< T >
供给型接口 :T get();
- 供给型接口Supplier,是一个只有产出,没有输入,就是只有返回值,没有参数(T get();)
Function< T , R >
函数式接口 :R apply (T t);
- 函数型接口Function<T,R>,是一个参数为T类型,返回值为R类型的接口(R apply(T t);)
Predicate< T >
断言型接口 :boolean test(T t);
- 断言型接口Predicate,是一个参数为T类型,返回值为boolean类型的接口(boolean test(T t);)
六、总结
为何使用: 使用lambda表达式可以让代码的可读性更强,同时代码更简洁。但lambda的意义不仅仅于此,这里只是最显而易见的好处。
何时使用: 当调用的方法中的某个参数为函数式接口的引用时,就可以使用lambda表达式为该接口引用提供一个具体实现。
实质: 接口的具体实现。只不过不需要单独编写类。