函数式接口是Stream流的操作引擎和生命周期支撑——filter用Predicate、map用Function、forEach用Consumer、generate用Supplier,接口类型决定行为边界,选错会导致编译失败或语义错误。

函数式接口是 Stream 流的“操作引擎”——Stream 本身不干活,真正执行过滤、转换、消费等动作的,全是背后绑定的函数式接口实例。
Stream 的每个操作都对应一个函数式接口
Stream 的中间操作和终止操作,本质上就是接收特定函数式接口作为参数,并调用其抽象方法:
-
filter() 接收
Predicate<t></t>:判断元素是否保留(test(T t)返回 boolean) -
map() 接收
Function<t r></t>:把一个类型元素转成另一个类型(apply(T t)返回 R) -
forEach() 接收
Consumer<t></t>:对每个元素执行副作用操作(accept(T t)无返回) -
findFirst() / findAny() 虽无显式参数,但内部依赖
Predicate配合Optional实现短路匹配 -
reduce() 使用
BinaryOperator<t></t>(即Function<t></t>)做累积计算
Lambda 和方法引用让接口调用变得轻量
没有函数式接口,你就得写一堆匿名内部类;有了它,就能用一行 Lambda 或方法引用完成逻辑表达:
比如筛选长度大于 2 的字符串:
立即学习“Java免费学习笔记(深入)”;
list.stream()
.filter(s -> s.length() > 2) // ← Predicate<String> 的 lambda 实现
.map(String::toUpperCase) // ← Function<String, String> 的方法引用
.forEach(System.out::println); // ← Consumer<String> 的方法引用
这三处看似简洁的写法,背后分别触发了 Predicate.test()、Function.apply()、Consumer.accept() 的调用。
Supplier 是流的源头,Consumer 是流的终点
流的生命周期两端也由函数式接口支撑:
- 创建无限流常用
Stream.generate(Supplier<t>)</t>:Supplier 的get()方法按需生成元素,比如Stream.generate(Math::random) - 收集结果常用
collect(Collectors.toMap(k -> k.name, v -> v.age)):其中 keyMapper 和 valueMapper 都是Function,而下游的Collector内部也封装了Supplier(容器工厂)、BiConsumer(累加器)、BinaryOperator(合并器) - 自定义终端操作时,
forEach、peek等都依赖Consumer实现“只用不返回”的语义
避坑关键:接口类型决定行为边界
选错函数式接口会导致编译失败或语义错误:
- 想转换类型却用了
Consumer→ 编译报错(它不返回值) - 在
filter里写了s -> { System.out.println(s); return true; }→ 语法合法,但属于Consumer+return混用,可读性差,应拆成peek+filter - 误把
Function当Supplier传给generate→ 编译不通过(前者要入参,后者不要)
所以写 Stream 代码前,先确认你要做的动作属于哪一类语义:判断?转换?消费?生成?再挑对应接口,就自然顺了。


















