在 Java8 之前当实现只有一个方法的接口我们通常是通过使用匿名内部类的方式来重写接口的方法以 Comparator 为例:

1
2
3
4
5
6
7
8
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println(list); // [1, 2, 3, 4, 5, 6]

Java8 中引入了 Lambda 表达式提供了更加简洁的语法:() -> {}

1
2
3
4
5
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Collections.sort(list, (Integer o1, Integer o2) -> {
return o1.compareTo(o2);
});
System.out.println(list); // [1, 2, 3, 4, 5, 6]

从 Java8 开始编译器可以从接口的方法签名中自动推导出参数类型因此可以省略掉类型的声明

1
2
3
4
5
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Collections.sort(list, (o1, o2) -> {
return o1.compareTo(o2);
});
System.out.println(list); // [1, 2, 3, 4, 5, 6]

当方法体只有一行代码时可以省略掉 {} 和 return 关键字以及代码行结束的分号;

1
2
3
List<Integer> list = Arrays.asList(1, 3, 5, 2, 4, 6);
Collections.sort(list, (o1, o2) -> o1.compareTo(o2));
System.out.println(list); // [1, 2, 3, 4, 5, 6]

对于只有一个抽象方法的接口都可以使用 Lambda 表达式为了确保接口符合要求可以使用 @FunctionalInterface 注解标注接口被 @FunctionalInterface 注解标注的接口(称为函数式接口)只允许存在一个抽象方法没有或多于一个抽象方法编译都将无法通过由于默认的方法不是抽象的因此函数式接口依然可以存在一个或多个默认方法。其中每个 Lambda 表达式都将匹配函数式接口的这个抽象方法Lambda 表达式的类型也由该接口类型决定

1
2
3
4
5
6
@FunctionalInterface
interface Operation<I, O> {
O calculate(I input);
}

对函数式接口使用 Lambda 表达式

1
2
3
4
5
public static void main(String[] args) {
Operation<Integer, Integer> square = (i) -> i * i;
Integer result = square.calculate(3);
System.out.println(result); // 9
}