理解 函数式接口(Functional Interface) 的定义与核心特征
掌握 @FunctionalInterface 注解的作用与使用规范
熟悉 Java 8 引入的四大核心函数式接口:Consumer、Predicate、Function、Supplier
能够结合 Lambda 表达式编写简洁、高效的代码
了解函数式接口在 Stream API 和集合操作中的典型应用场景
函数式接口是仅包含一个抽象方法的接口。这一特性使其能够与 Lambda 表达式 或 方法引用 无缝配合,从而简化代码结构。
关键点:只要接口中有且仅有一个抽象方法,它就是函数式接口——无论是否显式使用
@FunctionalInterface注解。
使用 Lambda 实现 Runnable
public class MainApp {
public static void main(String[] args) {
// 使用 Lambda 表达式实现 Runnable 接口
new Thread(() -> System.out.println("新线程已启动")).start();
}
}输出:
新线程已启动说明:
Runnable接口只有一个抽象方法run(),因此是函数式接口。Lambda 表达式() -> ...实际上就是对run()方法的实现。
@FunctionalInterface虽然该注解不是必需的,但强烈建议使用,因为它能帮助编译器在早期发现错误。
自定义函数式接口
@FunctionalInterface
interface Square {
int calculate(int x);
}
class MainApp {
public static void main(String[] args) {
int a = 5;
// 使用 Lambda 实现 calculate 方法
Square s = (int x) -> x * x;
int result = s.calculate(a);
System.out.println(result); // 输出:25
}
}如果在标注了
@FunctionalInterface的接口中添加第二个抽象方法,编译器将报错:
“Unexpected @FunctionalInterface annotation”。
在 Java 8 之前,必须使用匿名内部类来实现接口:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程已启动");
}
}).start();相比之下,Lambda 表达式显著减少了样板代码,提升了可读性。
Java 8 在 java.util.function 包中提供了大量预定义的函数式接口,广泛用于 Stream、集合和函数式编程。
Consumer<T>
作用:接收一个参数,无返回值(常用于打印、日志、副作用操作)
核心方法:void accept(T t)
变体:IntConsumer、DoubleConsumer、LongConsumer
Consumer<String> printer = value -> System.out.println(value);
printer.accept("Hello");
Predicate<T>
作用:接收一个参数,返回 boolean(常用于过滤条件)
核心方法:boolean test(T t)
变体:IntPredicate、DoublePredicate、LongPredicate
示例:过滤以 "G" 开头的字符串
import java.util.*;
import java.util.function.Predicate;
class MainApp {
public static void main(String[] args) {
List<String> names = Arrays.asList("Good", "God", "g1", "QA", "Goods");
Predicate<String> startsWithG = s -> s.startsWith("G");
for (String name : names) {
if (startsWithG.test(name)) {
System.out.println(name);
}
}
}
}
Function<T, R>
作用:接收一个参数,返回一个结果(常用于数据映射或转换)
核心方法:R apply(T t)
常见变体:
UnaryOperator<T>:输入输出类型相同(如 T -> T)
BiFunction<T, U, R>:接收两个参数,返回一个结果
BinaryOperator<T>:BiFunction 的特例,输入输出类型相同
Function<Integer, Integer> square = x -> x * x;
System.out.println(square.apply(4)); // 输出:16
Supplier<T>
作用:不接收参数,但返回一个结果(常用于工厂方法、延迟初始化)
核心方法:T get()
变体:BooleanSupplier、IntSupplier、DoubleSupplier、LongSupplier
Supplier<String> message = () -> "你好,世界!";
System.out.println(message.get()); // 输出:你好,世界!
函数式接口 = 仅含一个抽象方法 的接口。
@FunctionalInterface 是可选但推荐的编译期检查工具。
Lambda 表达式让函数式接口的实现变得极其简洁。
Consumer、Predicate、Function、Supplier 是最常用的四大函数式接口。
这些接口是 Java Stream API 的基石,广泛应用于集合的过滤、映射、遍历等操作。
为什么 Comparable 被视为函数式接口?它是否可以与 Lambda 表达式一起使用?请举例说明。
假设你需要对一个整数列表进行如下操作:只保留偶数,然后每个数平方,最后求和。请使用 Predicate、Function 和 Stream 完成该任务。
如果一个接口继承了两个函数式接口,且这两个父接口的抽象方法签名不同,那么子接口还是函数式接口吗?为什么?