Lambda表达式
Java的Lambda表达式形式为:
(params) -> { statements };
其中:
- 若params只有1个,可以省略():
param -> { statements };
- 若params为0个,用()表示无参数:
() -> { statements };
- 若代码为一行,则可省略{},无论该行代码是否为表达式:
(params) -> expression;
或(params) -> statement;
函数式接口
Lambda表达式本质上是一个对象。而对象就必然有其对应的类型,就像一个字符串其类型为String一样。
当一个函数,其参数需要传入一个Lambda表达式时,函数的参数就需要明确定义该Lambda表达式的类型。
实际上,Java的Lambda表达式都是归属于某个具体已定义的类型的。根据Lambda表达式的参数与返回值数量和类型,Java定义了一组interface来接收Lambda表达式,称之为函数式接口。
函数式接口有以下条件:
- 是一个interface。
- 有且仅有一个抽象方法。
另外:
- interface默认继承Java.lang.Object,故Object的抽象方法不包含在内。
- 可以使用@FunctionalInterface注解来标记函数式接口,有助于编译器进行检查。但@FunctionalInterface注解并非必须,只要满足条件,即使没有@FunctionalInterface注解编译器也会将接口识别为函数式接口。
例如:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Java8以后,Runnable接口多了@FunctionalInterface注解。这表示Runnable接口成为函数式接口了,可以接收Lambda表达式。
而实际上,由于Runnable接口有且仅有一个抽象方法,满足函数式接口的条件,所以即使不加@FunctionalInterface注解也依然会被识别为函数式接口。
所以可以自定义函数式接口:
@FunctionalInterface
public interface MyInterface {
// 定义唯一的抽象方法
void doWork();
// toString()属于Object,不包含
String toString();
}
使用:
MyInterface myInterface = () -> System.out.println("do work");
或将其作为参数类型:
class MyClass {
public void doMyWork(MyInterface myInterface) {
myInterface.doWork();
}
}
MyClass myClass = new MyClass();
myClass.doMyWork(() -> System.out.println("do work"));
前面提到的Runnable接口同理。
除了Runnable接口,Java8还提供了一组函数式接口:
接口 | 参数 | 返回类型 | 描述 |
---|---|---|---|
Predicate | T | boolean | 判断一个对象是否符合条件。常用于对象过滤。 |
Function<T, R> | T | R | 将一个对象转换为另一个对象。 |
Supplier | None | T | 提供一个对象。生产者-消费者中的生产者。 |
Consumer | T | void | 消费一个对象。生产者-消费者中的消费者。无返回值。 |
UnaryOperator | T | T | 接收对象并返回同类型的对象。 |
BinaryOperator | (T, T) | T | 接收两个对象,并返回一个原对象。这三个对象的类型都相同。 |
其中:
- Supplier是唯一无参数的函数。其他函数都必须传入参数。
- Consumer是唯一无返回的函数。其他函数都会返回一个对象。
Runnable接口则是无参数,无返回值的。