函数式接口
Lambda 不是孤立存在的。它需要一个"目标类型"——在 Java 里,这个目标类型就是函数式接口。
什么是函数式接口
只有一条抽象方法的接口。不信?翻开 JDK 源码看看 Runnable:
java
@FunctionalInterface
public interface Runnable {
void run();
}就这一个方法。Lambda 之所以能表示 Runnable,是因为它符合"单一抽象方法"的规则。
@FunctionalInterface 注解是给你的 IDE 看的——加上它,编译器会帮你检查这个接口是否真的只有一条抽象方法。漏掉了会报错,多于一条也会报错。
内置函数式接口一览
JDK 在 java.util.function 包里预置了最常用的类型:
Consumer<T> — 消费,不返回
java
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello"); // 打印 Hello,无返回值
// 变体:BiConsumer<T, U>
BiConsumer<String, Integer> printPair = (s, i) -> System.out.println(s + i);
printPair.accept("次数:", 5); // 次数: 5Supplier<T> — 不消费,只产出
java
Supplier<LocalDateTime> now = LocalDateTime::now;
LocalDateTime time = now.get();
// 等价于
LocalDateTime time = LocalDateTime.now();Function<T, R> — 吃进去 T,吐出来 R
java
Function<String, Integer> toLength = String::length;
toLength.apply("hello"); // 5
// 链式:andThen
Function<String, String> pipeline =
String::toUpperCase
.andThen(s -> s + "!");
pipeline.apply("hello"); // HELLO!Predicate<T> — 判断真假
java
Predicate<String> isEmpty = String::isEmpty;
isEmpty.test(""); // true
isEmpty.test("abc"); // false
// 组合:与、或、非
Predicate<String> notEmpty = isEmpty.negate();
Predicate<String> longEnough = s -> s.length() > 3;
Predicate<String> combined = notEmpty.and(longEnough);
combined.test("hello"); // true
combined.test("hi"); // false
combined.test(""); // falseOperator 系列 — 特殊 Function
| 类型 | 方法签名 | 说明 |
|---|---|---|
UnaryOperator<T> | T apply(T t) | 一元操作 |
BinaryOperator<T> | T apply(T t1, T t2) | 二元操作 |
IntUnaryOperator | int applyAsInt(int x) | 原始类型版本 |
IntBinaryOperator | int applyAsInt(int a, int b) | 原始类型版本 |
java
// UnaryOperator — 一元运算
UnaryOperator<Integer> doubleValue = n -> n * 2;
doubleValue.apply(5); // 10
// BinaryOperator — 二元运算
BinaryOperator<Integer> max = Math::max;
max.apply(3, 7); // 7
// 更常见的用法:reduce
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = nums.stream()
.reduce(0, Integer::sum); // BinaryOperator自定义函数式接口
当内置接口不够用时,自己写一个。
场景一:带返回值的回调
java
@FunctionalInterface
interface Transformer<T, R> {
R transform(T input);
}
// 使用
Transformer<String, Integer> toLength = String::length;
toLength.transform("hello"); // 5场景二:条件判断
java
@FunctionalInterface
interface Condition<T> {
boolean evaluate(T item);
}
// 用于筛选逻辑
List<String> longNames = names.stream()
.filter(name -> name.length() > 5) // 匿名 Lambda
.collect(Collectors.toList());
// 用自定义接口让代码更清晰
Condition<String> isLong = name -> name.length() > 5;
// 但说实话,这种场景用内置 Predicate 就行
Predicate<String> isLong2 = name -> name.length() > 5;场景三:带两个参数一个有返回值
java
@FunctionalInterface
interface Operation {
int execute(int a, int b);
}
Operation add = (a, b) -> a + b;
Operation multiply = (a, b) -> a * b;
System.out.println(add.execute(3, 4)); // 7
System.out.println(multiply.execute(3, 4)); // 12方法引用与函数式接口
方法引用本质上也是一种 Lambda,只是更简洁的形式。
java
import java.util.function.*;
// 静态方法引用
Function<String, Integer> f1 = Integer::parseInt; // s -> Integer.parseInt(s)
f1.apply("123"); // 123
// 实例方法引用(任意对象)
Function<String, String> f2 = String::toUpperCase; // s -> s.toUpperCase()
f2.apply("hello"); // HELLO
// 实例方法引用(特定对象)
String prefix = "Hello, ";
Function<String, String> f3 = prefix::concat; // s -> prefix.concat(s)
f3.apply("World"); // Hello, World
// 构造方法引用
Supplier<ArrayList<String>> f4 = ArrayList::new; // () -> new ArrayList<>()
f4.get(); // 一个新的 ArrayList
// 带参数的构造方法
Function<Integer, String[]> f5 = String[]::new; // n -> new String[n]
f5.apply(3); // 一个长度为 3 的 String 数组泛型函数式接口
函数式接口也可以是泛型的:
java
// 泛型函数式接口
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
// 使用
Converter<String, Integer> strToInt = Integer::parseInt;
Converter<Integer, String> intToStr = Object::toString;
Converter<List<String>, Set<String>> listToSet = list -> new HashSet<>(list);组合的艺术
函数式接口最强大的地方在于可以组合:
java
Predicate<String> isBlank = String::isBlank;
Predicate<String> isNotBlank = isBlank.negate();
Predicate<String> isLong = s -> s.length() > 5;
// 组合:既不为空,又要够长
Predicate<String> valid = isNotBlank.and(isLong);
valid.test("hello world"); // true
valid.test("hi"); // false
valid.test(""); // false
// Function 组合
Function<Integer, Integer> doubleValue = n -> n * 2;
Function<Integer, Integer> addOne = n -> n + 1;
// 先加倍再加一:addOne(double(3)) → addOne(6) → 7
Function<Integer, Integer> combined = doubleValue.andThen(addOne);
combined.apply(3); // 7
// compose:先执行参数里的,再执行外层的
// double(addOne(3)) → double(4) → 8
Function<Integer, Integer> composed = doubleValue.compose(addOne);
composed.apply(3); // 8什么不算抽象方法
一个接口里可能有其他方法,但它们不影响函数式接口的判定:
java
@FunctionalInterface
interface EnhancedComparator<T> {
int compare(T o1, T o2);
// default 方法不算——它有默认实现
default boolean equals(Object obj) {
return false;
}
}
// 这仍然是函数式接口,因为只有一条抽象方法小结
| 接口 | 核心方法 | 用途 |
|---|---|---|
Consumer<T> | void accept(T) | 执行操作,不返回值 |
Supplier<T> | T get() | 生产一个值 |
Function<T,R> | R apply(T) | 转换 |
Predicate<T> | boolean test(T) | 判断 |
UnaryOperator<T> | T apply(T) | 一元运算 |
BinaryOperator<T> | T apply(T, T) | 二元运算 |
优先使用 JDK 内置的——它们已经覆盖了 90% 的场景。只有在业务逻辑复杂、内置接口无法清晰表达意图时,才自定义函数式接口。
