第三章 Lambda表达式
理解
Lambda表达式可看做匿名函数的一种方式,它没有名称,但有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
组成
Lambda表达式有三个部分:
- 参数列表
- 箭头
- Lambda主体
// Simple example
Runnable r = () -> System.out.println("Hello!");
r.run();
函数式接口
在哪里可以使用Lambda呢?可以在函数式接口上使用Lambda表达式,函数式接口是指只定义一个抽象方法的接口
,java API中的函数式接口有 Comparator、Runnable等,也可以自定义函数式接口供自己使用。
// @FunctionalInterface是表示这是第一个函数式接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
当然,接口还可以拥有默认方法,哪怕有很多默认方法,只要接口只定义了一个抽象方法,就仍然是一个函数式接口。
函数式接口的作用:Lambda表达式允许直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。
人话:Lambda表达式是函数式接口的一个具体实现的实例,虽然使用匿名内部类也可以完成同样功能,不过很笨拙。
Runnable r1 = () -> System.out.println("Hello r1");
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("Hello r2");
}
};
r1.run();
r2.run();
函数描述符
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,我们将这种抽象方法叫做函数描述符。
人话:就是函数式接口的输入输出的表达,在写表达式时,表达式的输入和输出都与函数式接口抽象方法的输入输出相互对应上、相匹配。
如何使用函数式接口呢?
经过理解,我认为最主要的是把握其中要点为——将行为参数化。
例子1:希望拿到绿色苹果
public class Test {
public static void main(String[] args) {
List<Apple> inventory = Arrays.asList(new Apple(80,"green"),
new Apple(155, "green"),
new Apple(120, "red"),
new Apple(160, "yellow"));
// 3、实际应用 主要注意第二个参数使用了Lambda表达式
// 传递的是一种行为
List<Apple> apples = FilterApple(inventory, (Apple a) -> "green".equals(a.getColor()));
System.out.println(apples);
// [Apple{color='green', weight=80}, Apple{color='green', weight=155}]
}
// 2、利用函数式接口,写出想要的逻辑
public static List<Apple> FilterApple(List<Apple> inventory,Filter f){
List<Apple> result = new ArrayList<>();
for(Apple apple:inventory){
if(f.judge(apple)){
result.add(apple);
}
}
return result;
}
// 1、定义一个函数式接口
@FunctionalInterface
interface Filter{
boolean judge(Apple a);
}
}
但说实话现在还不是很能理解…还没有通透
例子2:是否能被2整除
public class Test {
public static void main(String[] args) {
// 2、实现,注意类别是 接口名CountNum
CountNum countnums = (int i) -> i%2==0;
System.out.println(countnums.count(199)); // false
}
// 1、定义一个函数式接口
@FunctionalInterface
interface CountNum{
boolean count(int i);
}
}
具体理解部分,可查看p49,类型检查流程,加深理解!
**ATTENTION:**前面目标类型CountNum是函数式接口,后面(int i) -> i%2==0
是Lambda表达式,注意两者关系。
一定要注意目标类型是否为函数式接口,以及后面表达式的返回类型是否与函数式接口的返回类型一致!!总体来说就是要注意函数描述符
在java 8中,已有很多常用的函数式接口,其函数描述符不同,可满足不同需求。
方法引用
方法引用可以被看做仅仅调用特定方法的Lambda的一种快捷写法。
基本思想:如果一个Lambda代表的只是 直接调用这个方法,那最好还是用名称来调用它,而不是去描述如何调用它。
如:
public class Test {
public static void main(String[] args) {
Apple blueApple = new Apple(77, "blue");
// 方法调用
// ShowColor showColor = (Apple a) -> a.getColor();
ShowColor showColor = Apple::getColor;
String appleblue = showColor.show(blueApple);
System.out.println(appleblue);
}
@FunctionalInterface
interface ShowColor{
String show(Apple a);
}
}
方法引用主要有三类:
- 指向静态方法的方法引用
- 指向任意类型实例方法的方法引用
- 指向现有对象的实例方法的方法引用
public class Test {
public static void main(String[] args) {
List<Apple> inventory = Arrays.asList(new Apple(80,"green"),
new Apple(155, "green"),
new Apple(120, "red"),
new Apple(120, "a"),
new Apple(160, "yellow"));
inventory.sort(Comparator.comparing(Apple::getWeight)
.thenComparing(Apple::getColor));
System.out.println(inventory);
// [Apple{color='green', weight=80}, Apple{color='a', weight=120}, Apple{color='red', weight=120}, Apple{color='green', weight=155}, Apple{color='yellow', weight=160}]
}
}