Java-lambda表达式、函数式接口、方法引用
1. Lambda表达式
1.1 Lambda概念
- 1.8的新特性
- 用来简化接口匿名内部类
1.2 使用前提(重点)
- 必须有接口且接口中有且只有一个抽象方法!!
1.3 标准格式
- (参数类型 参数名称) -> {
执行代码语句}
说明:
()
里面放接口中抽象方法的参数列表;->
新语法格式,代表指向动作;{}
里面放重写抽象方法的执行语句。
1.4 省略格式
- 省略规则
()
中的参数的数据类型可省略;- 如果参数列表只有一个参数时,小括号可省略;
- 若方法体只有一条语句时,可省略大括号,此时return和大括号后面的分号都必须省略!
1.5 示例代码
/*
无参无返回值
*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
}).start();
//使用lambda表达式转换匿名内部类//
new Thread(() -> {
System.out.println("hello");}).start();
//用省略格式写
new Thread(()->System.out.println("hello")).start();
/*
有参有返回值
*/
Collections.sort(list,new Comparator<Student>(){
@Override
public int compart(Student o1,Student o2) {
return o1.getScore() - o2.getScore();
}
});
//使用lambda标准格式
Collections.sort(list,(Student o1,Student o2) -> {
return o1.getScore() - o2.getScore();});
//使用lambda省略格式
Collections.sort(list, (o1,o2) ->o1.getScore() - o2.getScore());
1.6 小结(记住、理解)
- **(重点)**lambda就是
参数列表->重写方法体
。 - 在后面的函数式接口中,lambda就是
参数列表->重写的抽象方法
,一旦函数式接口实例调用抽象方法,执行的就是lambda的方法体。
2. 函数式接口
2.1 概念引入
-
函数式接口:有且只有一个抽象方法的接口
适用于函数式编程的场景,其体现正是Lambda表达式!
“语法糖”指原理不变而更为便捷的代码语法。
2.2 格式
-
正常格式:
修饰符 interface 接口名 { public abstract 返回值类型 方法名(参数列表); //其他非抽象方法内容 }
-
函数式接口简略格式:
public interface MyFunctionalInterface { void myMethod(); }
2.3 @FunctionalInterface注解
- 1.8的新注解,用于接口的定义上,并判断该接口是否有且只有一个抽象方法。若否,则报错。
- 该注解只为了让系统辅助检查接口,即使不用,只要接口满足函数式接口定义,该接口还是一个函数式接口。
2.4 无参无返回值的自定义函数式接口示例
定义:
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
应用:
public class Note {
private static void Test(MyFunctionalInterface mfi) {
mfi.myMethod();
}
public static void main(String[] args) {
Test(()->System.out.println("Do something!"));
//使用匿名内部类还原
Test(new MyFunctionalInterface() {
@Override
public void myMethod() {
System.out.println("Do something!");
}
});
}
}
示例解析:先定义一个自定义函数式接口。由于Test方法传入的参数是函数式接口的实现类对象,所以在调用静态方法Test()时,示例用Lambda表达式代替匿名内部类作为该对象,并重写抽象方法。
要理解为何在Lambda表达式外是写Test,因为main方法里调用的是Test方法,而不是mfi或者myMethod!后两者都只是调用Test方法所需要的东西,Lambda表达式已经充当后两者
2.5 有参有返回的自定义函数式接口示例
定义:
@FunctionalInterface
public interface Sumable {
int sum(int a, int b);
}
应用:
public class Note {
private static void countSum (int x, int y, Sumable cal) {
System.out.println(cal.sum(x, y));
}
public static void main(String[] args) {
countSum(1,2,(i,j)->i+j);
//使用匿名内部类还原
countSum(1, 2, new Sumable() {
@Override
public int sum(int a, int b) {
return a + b;
}
});
}
}
示例解析:同样定义一个函数式接口,调用静态方法countSum,第三个参数需要传入函数式接口的实现类对象,则用lambda表达式替代匿名内部类传入方法。
3. 函数式编程
3.1 Lambda的延迟执行
-
延迟执行:在需要的时候才执行
-
解决部分场景中某些代码执行后不一定被使用所导致的性能浪费的问题
3.2 Lambda作为参数和返回值
3.2.1 Lambda作为参数
- 当函数式接口作为方法参数时,可以用Lambda代替(比如Thread类的构造方法参数Runnable)。
3.2.2 Lambda作为返回值
- 同理,当函数式接口作为方法的返回值类型时,可以用Lambda代替。(比如用一个方法获取Comparator接口)。
4. 方法引用
4.1 概念引入
4.1.1 概念
-
1.8的新特性
-
通过类名或对象名引用已存在的方法以简化lambda表达式。
-
方法引用和方法调用时两种概念,方法调用时马上执行。而方法引用在没有执行函数式接口的抽象方法时,该抽象方法的重写方法并不会被执行。
4.1.2 格式
-
类名::方法名
-
对象名::方法名
看起来有点像方法调用的格式
4.1.3 原理
- 创建函数式接口的匿名内部类对象
- 重写函数式接口的抽象方法并在重写的方法中调用被引用的方法。
4.1.4 方法引用的四种类型
- 静态方法引用
- 对象方法引用
- 特定类型的实例方法引用
- 构造方法引用
4.1.5 方法引用优点
- 简化lambda表达式
- 重复利用已存在的方法
4.1.6 方法引用的使用场景(重点)
- 当lambda表达式仅是调用一个已存在的方法时,才可以使用方法引用简化lambda表达式!!
4.2 方法引用的四种类型(重点)
4.2.1 静态方法引用(通过类名引用)
-
语法格式:
ClassName::staticMethodName
(类名::静态方法名) -
使用场景
比如Lambda表达式:
array->ArrayUtils.getMax(array)
,可以简化成ArrayUtils::getMax
,注意观察规律 -
注意事项
-
被引用的方法和函数式接口中的抽象方法必须有相同的参数列表;
-
若函数式接口的抽象方法有返回值,则被引用的方法必须也有相同的返回值;
-
若函数式接口的抽象方法无返回值,被引用方法的返回值可有可无。
在使用前,需要判断上述条
-