Java | 掌握 Java 8 四大函数式接口:Consumer、Supplier、Predicate、Function
·
关注CodingTechWork
引言
Java 8 引入了 函数式编程(Functional Programming) 范式,极大地简化了代码结构,提升了可读性和可维护性。
其中,java.util.function 包是函数式编程的核心,它定义了大量函数式接口,使得我们可以使用 Lambda 表达式 或 方法引用 来传递行为。
本文将重点剖析其中最常用的四大接口:
| 接口名 | 功能描述 | 抽象方法 |
|---|---|---|
Consumer<T> | 接收参数,无返回值(消费型) | void accept(T t) |
Supplier<T> | 无参数,返回结果(供给型) | T get() |
Predicate<T> | 接收参数,返回布尔值(断言型) | boolean test(T t) |
Function<T,R> | 接收参数,返回结果(函数型) | R apply(T t) |
接口详解与源码分析
Consumer:数据消费者
定义与特点
- 作用:接收一个参数并执行某种操作,无返回值。
- 典型用途:打印日志、修改对象状态、遍历集合。
源码结构
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
示例:打印字符串列表
import java.util.List;
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printer = System.out::println;
List.of("Alice", "Bob", "Charlie").forEach(printer);
}
}
使用场景
- 日志记录
- 集合遍历(如
forEach) - 对象状态修改(如设置属性)
Supplier:数据提供者
定义与特点
- 作用:无输入参数,但返回一个值。
- 典型用途:延迟计算、生成默认值、提供工厂对象。
源码结构
@FunctionalInterface
public interface Supplier<T> {
T get();
}
示例:生成随机数
import java.util.function.Supplier;
import java.util.Random;
public class SupplierExample {
public static void main(String[] args) {
Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
System.out.println("Random: " + randomSupplier.get());
}
}
使用场景
- 延迟初始化(如
Optional.orElseGet(Supplier)) - 工厂模式(如
() -> new Object()) - 提供配置值或常量
Predicate:条件判断器
定义与特点
- 作用:接收一个参数,返回
boolean值。 - 典型用途:过滤、校验、条件判断。
源码结构
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
示例:过滤空字符串
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PredicateExample {
public static void main(String[] args) {
Predicate<String> notEmpty = s -> !s.isEmpty();
List<String> list = List.of("A", "", "B", " ", "C");
List<String> filtered = list.stream()
.filter(notEmpty)
.collect(Collectors.toList());
// [A, B, , C]
System.out.println(filtered);
}
}
使用场景
- 数据过滤(如
Stream.filter) - 参数校验
- 条件分支逻辑
Function:类型转换器
定义与特点
- 作用:接收一个参数,返回一个结果,支持类型转换。
- 典型用途:数据映射、类型转换、提取字段。
源码结构
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
示例:字符串转整数
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> strToInt = Integer::valueOf;
Integer result = strToInt.apply("123");
// 124
System.out.println(result + 1);
}
}
使用场景
- 数据转换(如 DTO → VO)
- 字段提取(如
User::getName) - 链式处理(如
compose、andThen)
接口对比总结
| 接口 | 输入 | 输出 | 功能描述 | 典型方法 |
|---|---|---|---|---|
| Consumer | ✅ | ❌ | 消费数据 | accept(T t) |
| Supplier | ❌ | ✅ | 提供数据 | get() |
| Predicate | ✅ | ✅(boolean) | 条件判断 | test(T t) |
| Function | ✅ | ✅ | 类型转换 | apply(T t) |
组合使用四大接口
import java.util.*;
import java.util.function.*;
public class CombineExample {
public static void main(String[] args) {
Supplier<List<String>> supplier = () -> List.of("apple", "banana", "pear", "grape");
Predicate<String> startsWithA = s -> s.startsWith("a");
Function<String, String> toUpper = String::toUpperCase;
Consumer<String> printer = System.out::println;
supplier.get().stream()
.filter(startsWithA)
.map(toUpper)
.forEach(printer);
}
}
输出:
APPLE
如何优雅地使用这些接口?
| 建议 | 说明 |
|---|---|
| ✅ 优先使用 Lambda | 简化匿名内部类写法 |
| ✅ 使用方法引用 | 如 System.out::println |
| ✅ 组合链式调用 | 如 andThen、compose |
| ✅ 自定义函数式接口 | 使用 @FunctionalInterface 注解 |
参考资料
更多推荐
所有评论(0)