Jakob Jenkov 2021-03-08
“Java 函数式接口”这一术语是在 Java 8 中引入的。Java 中的函数式接口是指仅包含一个抽象(未实现)方法的接口。函数式接口除了这个唯一的未实现方法外,还可以包含具有具体实现的默认方法(default methods)和静态方法(static methods)。
以下是一个 Java 函数式接口的示例:
public interface MyFunctionalInterface {
public void execute();
}
上述接口之所以被视为函数式接口,是因为它只包含一个方法,并且该方法没有实现。通常,Java 接口中的方法不包含实现,但可以通过默认方法或静态方法提供实现。下面是一个包含部分方法实现的函数式接口示例:
public interface MyFunctionalInterface2 {
public void execute();
public default void print(String text) {
System.out.println(text);
}
public static void print(String text, PrintWriter writer) throws IOException {
writer.write(text);
}
}
尽管该接口中包含了默认方法和静态方法,但由于它仍然只有一个未实现的方法(即 execute()),因此它依然是一个合法的函数式接口。
函数式接口可以用 Lambda 表达式实现
Java 函数式接口可以使用 Lambda 表达式 来实现。下面的例子展示了如何用 Lambda 表达式实现前面定义的 MyFunctionalInterface 接口:
MyFunctionalInterface lambda = () -> {
System.out.println("Executing...");
};
Java Lambda 表达式用于实现接口中的单个方法。为了让编译器知道 Lambda 表达式实现的是哪个方法,该接口必须仅包含一个未实现的方法——也就是说,它必须是一个函数式接口。
本文不会深入讲解 Lambda 表达式的细节。如需了解更多信息,请点击本节开头的链接。
Java 内置的函数式接口
Java 提供了一组为常见场景设计的内置函数式接口,因此你无需为每个小用途都自己定义新的函数式接口。以下将介绍一些 Java 中常用的内置函数式接口。
Function
Java 的 Function 接口(java.util.function.Function)是 Java 中最核心的函数式接口之一。它表示一个接收单个参数并返回单个结果的函数。其定义如下:
public interface Function<T, R> {
public R apply(T parameter);
}
实际上,Function 接口中还包含一些额外的方法,但这些方法都有默认实现,因此在实现 Function 接口时,你只需实现 apply() 方法即可。
下面是一个 Function 的实现示例:
public class AddThree implements Function<Long, Long> {
@Override
public Long apply(Long aLong) {
return aLong + 3;
}
}
该实现接收一个 Long 类型参数,并返回加 3 后的结果。使用方式如下:
Function<Long, Long> adder = new AddThree();
Long result = adder.apply((long) 4);
System.out.println("result = " + result); // 输出: result = 7
你也可以使用 Lambda 表达式来实现 Function 接口:
Function<Long, Long> adder = (value) -> value + 3;
Long resultLambda = adder.apply((long) 8);
System.out.println("resultLambda = " + resultLambda); // 输出: resultLambda = 11
可以看到,使用 Lambda 表达式将实现逻辑直接内联到变量声明中,代码更简洁,也更直观。
Predicate
Java 的 Predicate 接口(java.util.function.Predicate)表示一个接收单个参数并返回 boolean 值的函数。其定义如下:
public interface Predicate<T> {
boolean test(T t);
}
Predicate 接口也包含其他默认或静态方法,但你只需关注 test() 方法。
使用类实现 Predicate 的示例如下:
public class CheckForNull implements Predicate<Object> {
@Override
public boolean test(Object o) {
return o != null;
}
}
也可以使用 Lambda 表达式实现:
Predicate<Object> predicate = (value) -> value != null;
该 Lambda 表达式与上面的类实现功能完全相同。
UnaryOperator
UnaryOperator 是一个特殊的 Function,其输入和输出类型相同。它表示对单个参数进行操作,并返回同类型的值。
示例:
UnaryOperator<Person> unaryOperator = (person) -> {
person.name = "New Name";
return person;
};
UnaryOperator 常用于在函数式流处理链中对对象进行修改并返回。
BinaryOperator
BinaryOperator 表示一个接收两个同类型参数、并返回一个同类型结果的操作。常用于求和、相减、相乘等操作。
示例:
BinaryOperator<MyValue> binaryOperator = (value1, value2) -> {
value1.add(value2);
return value1;
};
Supplier
Supplier 表示一个不接收参数、但提供(生成)某个值的函数。也可以看作是一个工厂接口。
示例:
Supplier<Integer> supplier = () -> new Integer((int) (Math.random() * 1000D));
该 Supplier 每次调用都会返回一个 0 到 999 之间的随机整数。
Consumer
Consumer 表示一个接收参数但不返回任何结果的操作。典型用途包括打印、写入文件或网络等。
示例:
Consumer<Integer> consumer = (value) -> System.out.println(value);
该 Consumer 会将传入的整数值打印到控制台。