一、函数式接口
函数式接口就是只定义一个抽象方法的接口(不包含默认方法和静态方法),如下:
public interface EatInterface {
void eat();
}
上面接口添加默认方法和静态方法后还是函数式接口:
public interface EatInterface {
void eat();
default void eatApple(){
System.out.println("吃苹果");
}
static void eatFish(){
System.out.println("吃鱼");
}
}
函数式接口一般配合@FunctionalInterface注解使用,@FunctionalInterface表示着该接口会设计成一个函数式接口,不符合规范的话,就会编译报错。@FunctionalInterface注解和@Override注解一样,加与不加都不会有影响,只进行语法的校验。
二、Lambda表达式
Lambda定义一个函数式接口的实现,
示例:
Runnable接口就是一个函数式接口,下面是Runnable接口的匿名内部类的实现方式。
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Runnable接口的内名内部类实现");
}
});
thread.start();
}
下面是Runnable接口的Lambda表达式实现方式:
public static void main(String[] args) {
Thread thread = new Thread(()-> System.out.println("Runnable接口的lambda实现"));
thread.start();
}
可以看到Lambda方式实现函数式接口要简洁的多。
1、Lambda的语法
Lambda 表达式通常使用语法是:
(Type1 param1, Type2 param2, ...) -> {
statment1;
statment2;
//.............
return statmentM;
}
上面的lambda表达式语法是标准语法,下面介绍一些简化的使用:
1. 参数类型省略–绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型(包括泛型)。这样lambda表达式就变成了:
(param1,param2, ..., paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}
2. 当lambda表达式的参数有且只有一个,可以省略小括号。lambda表达式简写为:
param1 -> {
statment1;
statment2;
//.............
return statmentM;
}
3. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。lambda表达式简化为:
param1 -> statment
三、方法引用
方法引用就是我们的Lambda体已经有相关的方法实现类的话,我们就可以使用方法引用的方式直接调用
方法引用一共有三种格式:
静态方法引用:ClassName::staticMethod
某一个实例对象的方法的引用:objectName::instanceMethod
某一类型的任意对象的方法的引用:ClassName::instanceMethod
前两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。
比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。
最后一种方式,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。
比如String::toLowerCase等同于x->x.toLowerCase()。
方法引用示例:
package com.bxp.lambda;
public class Student {
private String name;
private String phone;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static Integer compareByAge(Student a, Student b){
return a.getAge() - b.getAge();
}
public Integer compareByAgeOfInstance(Student a, Student b){
return a.getAge() - b.getAge();
}
public Integer compareByAgeOfTypeInstance(Student b){
return this.getAge() - b.getAge();
}
public Student() {
}
public Student(String name, String phone, Integer age) {
this.name = name;
this.phone = phone;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", phone='" + phone + '\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) {
/*Thread thread = new Thread(()-> System.out.println("Runnable接口的lambda实现"));
thread.start();*/
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("唐三", "15746841547" ,24));
studentList.add(new Student("千道流", "15746841657" ,130));
studentList.add(new Student("尘心", "15746654147" ,100));
studentList.add(new Student("比比东", "15733211447" ,50));
studentList.add(new Student("宁风致", "15733211447" ,45));
// 静态方法引用
// Collections.sort(studentList, Student::compareByAge);
// 实例对象的方法的引用
// Student student = new Student();
// Collections.sort(studentList, student::compareByAgeOfInstance);
// 某一类型的任意对象的方法的引用,lambda表达式的第一个参数作为方法的调用者,其余参数作为方法的实参(顺序一一对应)
Collections.sort(studentList, Student::compareByAgeOfTypeInstance);
studentList.forEach(System.out::println);
}