一、函数式接口定义
函数式接口(Functional Interface) 是 Java 8 引入的核心概念,指有且仅有一个抽象方法的接口(可包含多个默认方法或静态方法)。使用 @FunctionalInterface
注解显式声明,编译器会强制检查接口是否符合规范。
@FunctionalInterface
interface MyFunctionalInterface {
void execute(); // 唯一抽象方法
default void log() { // 默认方法
System.out.println("Logging");
}
static void print() { // 静态方法
System.out.println("Static method");
}
}
二、四大核心函数式接口
Java 在 java.util.function
包中内置了常用函数式接口:
接口类型 | 函数式接口 | 抽象方法 | 用途 |
---|---|---|---|
消费型 | Consumer<T> | void accept(T t) | 接收参数无返回值 |
供给型 | Supplier<T> | T get() | 无参数返回结果 |
函数型 | Function<T,R> | R apply(T t) | 接收参数并返回结果 |
断言型 | Predicate<T> | boolean test(T t) | 条件判断 |
三、应用场景与代码示例
1. Lambda 表达式实现
// 消费型接口
Consumer<String> print = s -> System.out.println(s);
print.accept("Hello Consumer!");
// 供给型接口
Supplier<Double> random = () -> Math.random();
System.out.println(random.get());
// 函数型接口
Function<String, Integer> length = String::length;
System.out.println(length.apply("Java")); // 输出 4
// 断言型接口
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
2. Stream API 操作
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 过滤 (Predicate)
List<String> longNames = names.stream()
.filter(name -> name.length() > 4)
.collect(Collectors.toList()); // [Charlie]
// 转换 (Function)
List<Integer> nameLengths = names.stream()
.map(String::length)
.collect(Collectors.toList()); // [5, 3, 7]
3. 替代匿名内部类
// 传统写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Old way");
}
}).start();
// Lambda 简化
new Thread(() -> System.out.println("Lambda way")).start();
4. 条件分支处理
public void processUser(User user,
Predicate<User> validator,
Consumer<User> action) {
if (validator.test(user)) {
action.accept(user);
}
}
// 调用示例
processUser(currentUser,
u -> u.getAge() > 18,
u -> sendAdultNotification(u)
);
四、高级函数式接口
-
二元操作
BiFunction<T,U,R>
:接收两个参数返回结果
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
-
原始类型特化(避免装箱开销)
IntConsumer
,LongSupplier
,DoublePredicate
等
IntPredicate isPositive = i -> i > 0;
-
组合操作
Predicate<String> nonNull = s -> s != null; Predicate<String> longEnough = s -> s.length() > 5; Predicate<String> combined = nonNull.and(longEnough);
五、自定义函数式接口
@FunctionalInterface
interface StringProcessor {
String process(String input);
default StringProcessor chain(StringProcessor next) {
return s -> next.process(this.process(s));
}
}
// 使用示例
StringProcessor toUpper = String::toUpperCase;
StringProcessor addExclamation = s -> s + "!";
StringProcessor pipeline = toUpper.chain(addExclamation);
System.out.println(pipeline.process("hello")); // 输出 "HELLO!"
六、应用场景总结
场景 | 适用接口类型 | 示例 |
---|---|---|
集合过滤/条件判断 | Predicate | list.stream().filter() |
数据转换 | Function | list.stream().map() |
资源消耗型操作 | Consumer | list.forEach() |
延迟初始化/对象创建 | Supplier | Objects.requireNonNullElseGet() |
策略模式实现 | 自定义接口 | 不同算法实现 |
回调机制 | Runnable | 异步任务回调 |
七、最佳实践
- 优先使用内置接口:避免重复造轮子
- 避免副作用:保持 Lambda 表达式的纯净性
- 使用方法引用:简化代码(如
String::length
) - 组合接口:利用
and()
/or()
构建复杂逻辑 - 注意异常处理:在 Lambda 中妥善处理受检异常
函数式接口与 Lambda 表达式共同构成了 Java 函数式编程的基石,通过减少样板代码、提升表达力,显著提高了开发效率和代码可读性。